Curriculum/AI웹개발자_내일배움캠프

Story 6. Today I Learned (머신러닝)

작은코딩 2022. 1. 6. 19:45

1월 5일부터 다음 사물인식 프로젝트를 위해 머신러닝을 공부하기 시작했는데,, 개념 설명을 듣다가 너무 졸려서 졸음을 깨기 위해 몇 가지 공부법을 시도해봤다. 

 

이번 스토리는 어제, 오늘 머신러닝 공부를 위한 낙서장이라고 생각하고 가볍게 시작해보자!

 

* 경고 *

초보자가 강의 + 구글링을 통해 정리한 내용이라 두서가 없고 정확하지 않으니 미리 주의 바란다. 


첫번째! 필기

 

필기를 하면서 공부를 하니 그래도 강의만 들을 때보다는 덜 졸리고 이해도 잘 되었다. 

but,, 시간이 너무 오래걸린다 ㅠ 

다항논리회귀 파트에선 이해도 안돼서 필기 포기;;


두 번째! 강의 반복 시청!

 

다음은 강의를 무한 반복해서 시청을 했는데,, 이건 봐도 봐도 이해가 안 되고 봤던 내용을 또 보다 보니 지루하다 ㅠ


마지막 코드분석!!

 

머신러닝이고 뭐고 코드만 잘 쓰면 되는 거 아냐? 해서 든 생각,

바로 이거다!! 대충 개념을 머리에 때려 박았으니 나는 코드만 파해쳐서 훔쳐 가는 거다!!

1. 선형회귀 실습 숙제 (Linear Regression)

from tensorflow.keras.models import Sequential # tensorflow, keras sequential(선형)모델 시작하기
from tensorflow.keras.layers import Dense # 신경망 만들기 input - hidden(output&input) -output 구조
from tensorflow.keras.optimizers import Adam, SGD # 최소화 

# as -> 약어 만들기

# 넘파이/ 행렬이나 대규모 다차원 배열을 쉽게 처리 할 수 있도록 지원하는 파이썬의 라이브러리.
import numpy as np # 데이터 구조 외에도 수치 계산을 위해 효율적으로 구현된 기능을 제공.

# pandas 행과 열로 구성되어 있는 DataFrame type 데이터를 입력, 처리, 조작할 때 매우 강력하고 편리한 라이브러리 
import pandas as pd # 여기선 csv 파일 여는 용도


import matplotlib.pyplot as plt # 그래프

# Seaborn은 Matplotlib을 기반으로 다양한 색상 테마와 통계용 차트 등의 기능을 추가한 시각화 패키지이다.
import seaborn as sns # 그래프

from sklearn.model_selection import train_test_split # 머신러닝 도와주는 패키지 (트레이닝셋, 테스트셋 분류 가능 클래스)

대충 세팅은 이렇다. 실습을 코랩(?) 콜랩(?)에서 진행하다 보니 웬만한 패키지는 설치가 되어있어서 파이참에서 작업할때는 필요한 패키지를 다운받아야 한다.


# DataFrame 만들고 자료 확인하기
df = pd.read_csv('Salary.csv') # pandas library의 read_csv() 함수를 사용 / csv 파일을 불러와 DataFrame으로 저장

df.head(5) # 데이터 앞에서 5번째

# 데이터 크기 확인
print(df.shape) # 대충 (35, 2) 요런모양으로 나온다 (행, 열)

# 데이터 그래프로 확인하기
sns.pairplot(df, x_vars=['YearsExperience'], y_vars=['Salary'], height=4)

- pairplot에 대한 설명

 

다차원 실수형 데이터

만약 3차원 이상의 데이터라면 seaborn 패키지의 pairplot 명령을 사용한다. pairplot은 데이터프레임을 인수로 받아 그리드(grid) 형태로 각 데이터 열의 조합에 대해 스캐터 플롯을 그린다. 같은 데이터가 만나는 대각선 영역에는 해당 데이터의 히스토그램을 그린다.

 

분명 내가 사용한건 이런게 아니였는데,,, (2차원만 사용해서 그런가?)

 

2차원 실수 데이터면 jointplot을 사용해도 될거같다


# 우리가 사용할 데이터는 numpy.배열이다 / 데이터 타입은 float32비트
# 대괄호를 하나만 쓰고 출력하면 열 테이블에 숫자가 안찍힌다.

x_data = np.array(df[['YearsExperience']], dtype=np.float32) 
y_data = np.array(df[['Salary']], dtype=np.float32)

print(x_data.shape) # (35, 1) / 대괄호를 하나만 썻다면? : (35,) <- 요런식으로 나온다.
print(y_data.shape) # (35, 1)

강의에서는 keras는 np.array를 입력으로 받는다고 해서 무조건 numpy만 받아야 되나 했는데,,,

 

깃헙에서 케라스 팀 문서를 보면 인자로 numpy 배열만 받는 게 아니라 다른 데이터 폼도 써있다.

(결국 그게 numpy 배열인가,,???)

 

 

https://github.com/keras-team/keras-docs-ko/blob/master/sources/models/sequential.md

 

GitHub - keras-team/keras-docs-ko: Korean translation of the Keras documentation.

Korean translation of the Keras documentation. Contribute to keras-team/keras-docs-ko development by creating an account on GitHub.

github.com


# reshape는 배열과 차원을 변형해준다.
x_data = x_data.reshape((-1, 1))
y_data = y_data.reshape((-1, 1))

print(x_data.shape) # (35, 1)
print(y_data.shape) # (35, 1)



################# 3차원 변환 예시#################

a = np.arange(1,9) # 1~8까지의 배열
b = a.reshape(2,2,2) # 3차원 변환!

#b
## array([[[1,2], [3,4]], [[5, 6], [7, 8]]]) 

#b[0] # 첫 번째 행렬
## array([[1, 2], [3, 4]])

#b[0][0,1] # 첫 번째 행렬의 1행 2열 값 인덱싱 # 인덱싱이라는 말은 왜쓰는거지??
## 2

reshape함수는 np.reshape(변경할 배열, 차원) 또는 배열.reshape(차원)으로 사용 할 수 있으며, 현재의 배열의 차원(1차원,2차원,3차원)을 변경하여 행렬을 반환하거나 하는 경우에 많이 이용되는 함수이다.

 

내가 이해한 차원은 

1차원 : 행이나 열에 들어있는 data 

2차원 : 행과 열이 있는 data 

3차원 : 행렬안에 행과 열이 있는 data

그리고 차원 단계를 [] 대괄호로 표현한다?

 

그래서 배열을 구성해줄 때  

x_data = np.array(df[['YearsExperience']], dtype=np.float32) 

대괄호를 하나만 쓰면 2차원 구성이 되다 만느낌이어서 (32 ,) 요롷게 출력되나??

그럼 3개를 쓰면 어떻게 되지?? 

 

(결과가 궁금하다면? 더보기!)

더보기

뭐긴 뭐야! 에러지!!  ㅋㅋㅋㅋㅋㅋㅋ

x_data = np.array(df[[['YearsExperience']]], dtype=np.float32) 

KeyError: "None of [Index([('YearsExperience',)], dtype='object')] are in the [columns]"

 

대충 칼럼에 정보 없다는거 같은데, 나중에 자세히 찾아봐야겠다.

 

컴퓨터가 이해하는 구조로는 항상 행이 앞에 열이 다음에 오는거 같다.

거꾸로 되짚어 보면 행렬은 3차원, 행렬에서 행과 열만 빼내면 2차원, 행과 열도 각각 빼놓으면 1차원

 

이게 맞는건진 모르겠다. ㅎㅎ 

혹시 이 글을 보는 사람이 있다면 반드시!! 교차검증을 할 것!


# 데이터 셋 분할! // 트레인 셋과 검증 셋으로 나눈다.
x_train, x_val, y_train, y_val = train_test_split(x_data, y_data, test_size=0.2, random_state=2022)

print(x_train.shape, x_val.shape) # (28, 1) (7, 1)
print(y_train.shape, y_val.shape) # (28, 1) (7, 1)


# 데이터 셋을 여러개로 분할하고 싶으면 아래와 같이 또 분할하면 된다!
x_val, x_test, y_val, y_test = train_test_split(x_val, y_val, test_size=0.5, random_state=2022)

print(x_train.shape, x_val.shape, x_test.shape) # (28, 1) (3, 1) (4, 1)
print(y_train.shape, y_val.shape, y_test.shape) # (28, 1) (3, 1) (4, 1)

 

scikit learn에서 사용하는 random_state 인자는 수행시마다 동일한 결과를 얻기 위해 적용합니다.
train_test_split(..., test_size=0.2) 과 같은 함수는 80% train, 20% test 데이터 세트를 추출합니다. 하지만 추출된 데이터는 수행을 할때마다 다를수 있습니다. random하게 추출하기 때문입니다.
가령 1~ 100까지 일련번호로 된 100개의 데이터를 train_test_split(.., test_size=0.2) 로 수행하면 해당 함수를 첫번째 수행할 때는 1~80 번이 train, 81~100번이 test가 될 수 있지만, 다시 수행하면 이번에 21~100번이 train, 1~20번이 test가 될 수 있습니다. 80%, 20% 로 나누는건 동일하지만 함수를 수행 시마다 추출한 레코드들을 달라질수 있습니다. 내부적으로 random 함수를 적용합니다.
random_state=1 이라고 하면 바로 이 random 함수의 seed 값을 고정시키기 때문에 여러번 수행하더라도 같은 레코드를 추출합니다. random 함수의 seed값을 random_state라고 생각하시면 됩니다.
제가 강의에 사용된 train/test 데이터세트를 여러분도 동일하게 사용할 수 있도록 random_state를 고정값으로 할당했습니다. 그렇지 않으면 제가 설명드리는 데이터 세트와 여러분이 수행하는 데이터 세트는 80%, 20%는 맞더라도 서로 다른 레코드로 추출되기 때문입니다.
random_state를 어떤 값으로 하셔도 상관없습니다. 이는 random값을 고정하는 역할만 수행합니다.

 

그렇구만!! 역시 구박사님은 모르는게 없네~

 


model = Sequential([
                    Dense(1)
])

# compile 메소드 : 모델을 학습시키키 이전에 학습 방식에대한 환경설정
model.compile(loss='mean_squared_error', optimizer=Adam(lr=2200))
# loss : 학습에 사용할 손실 함수를 지정
# optimizer : 학습에 사용할 최적화 함수를 지정
# ls : learning rate 학습률 설정 // 보폭이라 불리기도 함

# fit 메소드 : 학습
model.fit(
    x_train,
    y_train,
    validation_data=(x_val, y_val),
    epochs=100
)

# x : 입력 데이터
# y : 목표 데이터
# epochs : int. 모델에 데이터 세트를 학습시킬 횟수 // 
# 한 번의 에폭은 훈련 데이터로 주어진 모든 x와 y를 각 1회씩 학습시키는 것을 뜻함
# validation_data : 매 에폭이 끝날 때마다 손실 및 평가지표를 측정할 검증 데이터를 지정한다. //
# 검증데이터는 오직 측정에만 활용되며 학습에는 사용되지 않는다.

 

입출력을 모두 연결해주는 Dense 레이어

Dense 레이어는 입력과 출력을 모두 연결해줍니다. 예를 들어 입력 뉴런이 4개, 출력 뉴런이 8개있다면 총 연결선은 32개(4*8=32) 입니다. 각 연결선에는 가중치(weight)를 포함하고 있는데, 이 가중치가 나타내는 의미는 연결강도라고 보시면 됩니다. 현재 연결선이 32개이므로 가중치도 32개입니다.

 

주요 인자는 다음과 같습니다.

  • 첫번째 인자 : 출력 뉴런의 수를 설정합니다.
  • input_dim : 입력 뉴런의 수를 설정합니다.
  • init : 가중치 초기화 방법 설정합니다.
    • ‘uniform’ : 균일 분포
    • ‘normal’ : 가우시안 분포
  • activation : 활성화 함수 설정합니다.
    • ‘linear’ : 디폴트 값, 입력뉴런과 가중치로 계산된 결과값이 그대로 출력으로 나옵니다.
    • ‘relu’ : rectifier 함수, 은익층에 주로 쓰입니다.
    • ‘sigmoid’ : 시그모이드 함수, 이진 분류 문제에서 출력층에 주로 쓰입니다.
    • ‘softmax’ : 소프트맥스 함수, 다중 클래스 분류 문제에서 출력층에 주로 쓰입니다.

# 결과를 그래프로 시각화

# predict : 모델에 표본을 입력하여 예측값을 생성. 계산은 배치 단위로 실행
y_pred = model.predict(x_val)
y_result = model.predict(x_test)


# scatter plot : 각각 단변수와 이변수 값을 시각화하는 가장 기본적인 그래프 중 하나.
plt.scatter(x_val, y_val, color='b')
plt.scatter(x_val, y_pred, color='g')
plt.show()

plt.scatter(x_test, y_test, color='b')
plt.scatter(x_test, y_result, color='r')
plt.show()

plt.scatter(x_test, y_test, color='b')
plt.scatter(x_val, y_val, color='b')
plt.scatter(x_test, y_result, color='r')
plt.scatter(x_val, y_pred, color='g')
plt.show()

데이터가 적어서 그런가 입력값이 커질수록 오차가 커진다

 

y_pred = model.predict([[20]]) # input에 직접 입력하면 바로 출력값을 알려준다.

print(y_pred) # 218650.58 (20년차면 대충 2억은 받는다는 소리??)

 


 

어렵다 어려워,, 

논리회귀까지 끝내려고 했는데 내일 과제로 남겨둬야겠다.

그래도 이렇게 구글링을 하면서 정리를 하니 코드 구성에 있어서는 어느정도 감이 잡힌다.

그래도 응용 부분은,,,,

앞으로 실습을 반복하며 활용법을 익혀야겠다.

 

머신러닝 1주차 숙제!

https://colab.research.google.com/drive/1Lg3t57C0qGm2KJ1GjerD_9KryI27PJaN?usp=sharing 

 

머신러닝 1주차 숙제.ipynb

Colaboratory notebook

colab.research.google.com

 

- 끝 -