[CHAPTER 14] Machine Learning
기계 학습(Machine Learning)
기계학습(Machine Learning)은 인공 지능의 한 분야로 컴퓨터에 학습 기능을 부여하기 위한 연구 분야이다.
'스스로 학습' 한다는 점이 가장 큰 특징이다.
기계 학습의 종류
지도 학습(supervised learning)
컴퓨터는 사람에 의해 주어진 예제와 정답을 제공받는다.
입력을 출력에 매핑하는 일반적인 규칙을 찾아 학습한다.
ex) 강아지와 고양이의 이미지를 제공하고 어떤 데이터가 강아지인지 고양이인지 사람이 알려준다.
자율 학습(unsupervised learning)
외부에서 정답(레이블)이 주어지지 않고 학습 알고리즘이 스스로 입력에서 어떤 구조를 발견하는 학습이다.
자율 학습의 대표적인 것이 클러스터링(clustering)이다.
아래의 데이터를 보고 컴퓨터가 스스로 학습한다.
ex) 구글 뉴스에서 비슷한 뉴스를 자동으로 그룹핑함.
강화 학습(reinforcement learning)
강화 학습은 보상 및 처벌의 형태로 학습 데이터가 주어진다.
ex) 바둑에서 어떤 수를 두어서 승리하였다면 보상이 주어지는 방식이 될 수 있다.
알파고가 이 방법을 이용했다.
지도 학습
지도 학습 중에서 회귀와 분류에 대해 살펴보자.
회귀
회귀(regression)란 일반적으로 데이터들을 다차원 공간에 표시한 후에 이 데이터들을 가장 잘 설명하는 직선이나 곡선을 찾는 문제라고 할 수 있다.
일반적으로 데이터를 학습시킬 때, 데이터의 어떤 특징을 추출하여 이것으로 학습시키고 테스트한다.
기계 학습 라이브러리 중 하나인 사이킷런(scikit-learn)을 사용하여 선형 회귀 분석을 해보자!!
학생의 키 예측하기
어떤 학생의 키를 예측하는 코드를 짜 보자.
linear_model.LinearRegression()으로 선형 회귀 모델을 생성한다.
import numpy as np
from sklearn import linear_model # scikit-learn 모듈을 가져온다
regr = linear_model.LinearRegression() # 선형 회귀 모델을 생성
학습할 데이터를 입력하고 fit() 함수를 이용해 학습을 한다.
다중 회귀 분석을 실시하기 위해서 반드시 2차원 배열이어야 한다. sklearn은 X의 각 항목을 스칼라 값이 아니라 다수의 종속 변수를 포함하는 벡터로 간주하기 때문이다.
X = [[164], [179], [162], [170]] # 다중회귀에도 사용하도록 함
y = [53, 63, 55, 59] # y = f(X)의 결과
regr.fit(X, y)
fit()을 이용해 찾은 직선의 기울기와 절편을 알아보자.
score() 함수를 이용해 X에 대해 y를 예측하는 데에 얼마나 적합한지 알 수 있다. 1에 가까울수록 좋은 것이다.
coef = regr.coef_ # 직선의 기울기
intercept = regr.intercept_ # 직선의 절편
score = regr.score(X, y) # 학습된 직선이 데이터를 얼마나 잘 따르나
print("y =", coef, "* X + ", intercept)
print("The score of this line for the data: ", score)
y = [0.55221745] * X + -35.686695278969964 The score of this line for the data: 0.903203123105647 |
predict() 함수를 이용해 키가 180인 학생과, 185인 학생의 몸무게를 예측해보자.
input_data = [ [180], [185] ]
result = regr.predict(input_data)
print(result)
[63.71244635 66.47353362] |
180인 학생은 63.7kg 185인 학생은 66.4kg 정도로 예측하고 있다.
머신러닝이란거 별거 없는거 같다.
위에서 한 짓들을 시각화해보자.
import matplotlib.pyplot as plt
import numpy as np
from sklearn import linear_model # scikit-learn 모듈을 가져온다
regr = linear_model.LinearRegression()
X = [[164], [179], [162], [170]] # 선형회귀의 입력은 2차원으로 만들어야 함
y = [53, 63, 55, 59] # y = f(X)의 결과값
regr.fit(X, y)
# 학습 데이터와 y 값을 산포도로 그린다.
plt.scatter(X, y, color='black')
# 학습 데이터를 입력으로 하여 예측값을 계산한다.
y_pred = regr.predict(X)
# 학습 데이터와 예측값으로 선그래프로 그린다.
# 계산된 기울기와 y 절편을 가지는 직선이 그려진다
plt.plot(X, y_pred, color='blue', linewidth=3)
plt.show()
분류
아래의 데이터에 새로운 초록색 데이터가 들어왔을 때, 어떤 집단에 속하는지 정해야 한다. 이 과정을 분류(classification)라고 한다.
k-NN 알고리즘
k-NN 알고리즘은 가장 가까운 k개의 도형을 확인한다.
k=3 일 때, class A가 1개 class B가 2개 이기 때문에 빨간색은 class B로 분류된다.
k=5 일 때, class A가 4개 class B가 2개 이기 때문에 빨간색은 class A로 분류된다.
붓꽃 분류
sk-learn.datasets 에 있는 iris 꽃의 데이터를 불러오자.
from sklearn.datasets import load_iris
iris = load_iris()
print(iris.data)
[[5.1 3.5 1.4 0.2] [4.9 3. 1.4 0.2] [4.7 3.2 1.3 0.2] [4.6 3.1 1.5 0.2] [5. 3.6 1.4 0.2] [5.4 3.9 1.7 0.4] [4.6 3.4 1.4 0.3] [5. 3.4 1.5 0.2] [4.4 2.9 1.4 0.2] [4.9 3.1 1.5 0.1] ... ... [5.9 3. 5.1 1.8]] |
iris.data의 shape
>>> iris.data.shape
(150, 4)
iris.target은 정답 레이블이다. 0은 setosa, 1은 versicolor, 2는 virginica를 뜻한다.
>>> iris.target
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
샘플 데이터가 가지는 4개의 특징 이름
>>> print(iris.feature_names)
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
위의 정보들을 보면 데이터는 아래와 같이 생겼을 것이다.
이제 iris 데이터중 80%를 train 데이터, 20%를 test 데이터로 분류하자.
train_test_split()을 이용하여 나눌 수 있다.
# (80:20)으로 분할한다.
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target,test_size=0.2)
k-NN 알고리즘을 적용하여 n_neighbors을 1, 3, 5, 10, 20, 30으로 설정하여 정확도를 출력해 보자.
n_neighbors가 k값을 결정하는 인자이다.
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
for i in [1, 3, 5, 10, 20, 30]:
num_neigh = i
knn = KNeighborsClassifier(n_neighbors = num_neigh)
knn.fit(X_train, y_train)
y_pred = knn.predict(X_test)
scores = metrics.accuracy_score(y_test, y_pred)
print('n_neighbors가 {0:d}일때 정확도: {1:.3f}'.format(num_neigh, scores))
.n_neighbors가 1일때 정확도: 0.900 n_neighbors가 3일때 정확도: 0.900 n_neighbors가 5일때 정확도: 0.933 n_neighbors가 10일때 정확도: 0.933 n_neighbors가 20일때 정확도: 0.933 n_neighbors가 30일때 정확도: 0.900 |
일반적으로 k가 증가함에 따라 정확도가 증가하지만 너무 커질 경우에는 다시 감소하는 경향이 있다.
새로운 꽃을 생성하고 그 꽃을 분류해보자.
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
iris = load_iris()
knn = KNeighborsClassifier(n_neighbors=6)
knn.fit(iris.data, iris.target)
classes = {0:'setosa', 1:'versicolor', 2:'virginica'}
# 아직 보지 못한 새로운 데이터를 생성
X = [[3, 4, 5, 2], [5, 4, 2, 2]] # 2개의 데이터를 생성
y = knn.predict(X) # 분류
print(classes[y[0]])
print(classes[y[1]])
versicolor setosa |
새로운 2개의 데이터는 각각 versicolor, setosa로 분류되었다.
오차
분류에서 사용했던 코드를 가져와 오차를 구해보자.
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
from sklearn.metrics import mean_squared_error
num_neigh = 6
knn = KNeighborsClassifier(n_neighbors = num_neigh)
knn.fit(X_train, y_train)
y_pred = knn.predict(X_test)
print(mean_squared_error(y_test, y_pred))
0.933 |
mean_squared_error() 함수는 평균 제곱 오차를 구해준다.
정답과 예측값의 차이를 제곱하여 더하고 평균을 내는 방법이다.
이 값이 클수록 오차가 크다는 뜻, 그러니까 성능이 좋지 않다는 뜻이다.
과적합(overfitting) 과소적합(underfitting)
과적합(overfitting)이란 학습하는 데이터에서는 성능이 뛰어나지만 새로운 데이터에 대해서는 성능이 잘 나오지 않는 모델을 만들어내는 일이다.
이와 반대로 과소적합(underfitting)은 데이터에 대한 학습이 지나치게 대충 이루어져 학습 데이터와 다른 데이터 모두에 대해 예측을 제대로 하지 못하는 모델을 만드는 일이다.
과소적합일 때는 입력의 특징을 늘려보고 모델을 복잡하게(차원을 높이기) 만들어보자
과적합일 때는 데이터를 늘리고, 정칙화를 적용하면 된다고 하는데..
정칙화는 과적합 방지를 위해 어떤 기준에 따라 벌점 정보를 추가하는 일이다.
지금 까지 배운 것들로
기대 수명 예측하기
캐글에서 가져온 데이터이다. 아래 깃허브 사이트에 있다.
https://github.com/dongupak/DataSciPy/blob/master/data/csv/life_expectancy.csv
이 데이터는 WHO에서 내어 놓은 각 나라별 기대수명 데이터로 2010년부터 2015년까지 나라별 기대수명과 보건예산, 질병 통계, 비만도 등이 정리되어 있다.
Life expectancy : 기대 수명,
Alcohol : 1인당 알코올 소비량,
BMI : 전인구의 평균 체질량 지수,
Percentage expenditure : GDP 대비 보건 예산 지출 비율
등등 여러 가지 데이터가 있다.
데이터중 원하는 부분만 추출해 보자.
import pandas as pd
import seaborn as sns
life = pd.read_csv(
'https://raw.githubusercontent.com/dongupak/DataSciPy/master/data/csv/life_expectancy.csv'
)
life = life[['Life expectancy', 'Year', 'Alcohol',
'Percentage expenditure', 'Total expenditure',
'Hepatitis B', 'Measles', 'Polio', 'BMI', 'GDP',
'Thinness 1-19 years', 'Thinness 5-9 years']]
life.dropna(inplace=True)
결손 값은 모두 삭제하였다.
지금 추출한 특징들 사이에 어떤 상관관계를 가지고 있는지 분석하여 보자.
판다스의 데이터 프레임에 corr() 함수를 적용할 수 있다.
corr() 함수는 데이터 프레임의 열 사이의 상관관계를 찾는다.
seaborn의 heatmap() 함수를 이용하여 연관 행렬을 그려보자.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
life = pd.read_csv(
'https://raw.githubusercontent.com/dongupak/DataSciPy/master/data/csv/life_expectancy.csv'
)
life = life[['Life expectancy', 'Year', 'Alcohol',
'Percentage expenditure', 'Total expenditure',
'Hepatitis B', 'Measles', 'Polio', 'BMI', 'GDP',
'Thinness 1-19 years', 'Thinness 5-9 years']]
life.dropna(inplace=True)
sns.set(rc={'figure.figsize': (12, 10)})
correlation_matrix = life.corr().round(2)
sns.heatmap(data=correlation_matrix, annot=True)
plt.show()
값이 낮거나 색이 진할수록 상관관계가 낮다는 뜻이다.
첫 번째 행을 보면 기대수명과 상관관계가 높은 것은 무엇인지 추측할 수 있다.
기대 수명에 크게 영향을 미치지 않는 데이터를 모두 포함시키면 신뢰도가 떨어진다.
위의 분석을 바탕으로 'Alcohol', 'Percentage expenditure', 'Polio', 'BMI', 'GDP', 'Thinness 1-19 years' 만을 추출하자
test, train 데이터를 8:2 비율로 나누고 간단한 회귀 모델을 만들어보자.
test 데이터에 대해 predict()를 적용하여 y_test_predict를 구하고
y_test_predict와 y_test 사이의 오차를 구해보자.
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.metrics import accuracy_score
# 데이터 읽기
life = pd.read_csv(
'https://raw.githubusercontent.com/dongupak/DataSciPy/master/data/csv/life_expectancy.csv'
)
# 결손값 삭제
life.dropna(inplace=True)
# 원하는 데이터 추출
X = life[['Alcohol', 'Percentage expenditure', 'Polio', 'BMI', 'GDP', 'Thinness 1-19 years']]
y = life['Life expectancy']
# train, test 나누기
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# 회귀 모델 생성
lin_model = LinearRegression()
lin_model.fit(X_train, y_train)
# 예측
y_test_predict = lin_model.predict(X_test)
# 오차값
rmse = np.sqrt(mean_squared_error(y_test, y_test_predict))
print('RMSE =', rmse)
RMSE = 6.134939377814806 |
RMSE는 Root Mean Squared Error로 MSE 값에 제곱근을 적용한 것이다.
이러한 머신러닝 방식으로 컴퓨터가 스스로 학습하고 결과값을 예측할 수 있다.
요즘 많이 쓰이는 딥러닝 방식의 머신러닝 알고리즘은 스스로 학습할 뿐만 아니라 특징들 까지도 스스로 추출해낸다.
다음 챕터에서는 tensorflow를 이용하여 딥러닝 알고리즘을 배워볼 것이다.
기대된다!!