우리는 이때까지 파이썬에 대해 공부해왔다.
여러 라이브러리들을 사용해보고, 다양한 데이터를 분석하는 것에 초점을 두었다.
이번에는 데이터를 기반으로 학습을 수행하는 기계학습의 원리를 알아보자.
파이썬은 이러한 기계학습을 공부하는 것에 있어서도 다양한 라이브러리를 지원해준다.
우리는 그 중 하나인 sckit-learn 을 이용하여 간단한 분석을 진행해보겠다.
우선 기계학습에 대해 알아보자.
컴퓨터가 사람처럼 스스로 배울 수 있다면 어떻게 될까?
우리는 이때까지 컴퓨터에게 특정 작업을 시키기 위해 프로그램을 작성하고 지시하였다.
하지만 컴퓨터가 데이터를 기반으로 스스로 학습할 수 있다면
컴퓨터는 더욱 더 복잡한 일을 할 수 있을 것이다.
예를 들면 알파고와 이세돌의 바둑 경기가 그렇다.
알파고에게 바둑 경기의 규칙과 이전 경기의 기보를 데이터로 입력해주었고,
스스로 바둑의 원리를 학습하여 바둑을 두었다.
출처 : https://news.sbs.co.kr/news/endPage.do?news_id=N1003469192
기계학습은 인공 지능의 한 분야로, 1959년에 Arthur Samuel 에 의해 만들어졌다.
기계학습은 주어진 데이터를 보고 컴퓨터가 판단 방법을 학습하게 만드는 것이다.
학습에 사용할 수 있는 데이터가 많아지면 판단을 내리는 알고리즘 성능이 향상될 것이다.
기계학습에는 다양한 학습법이 존재한다.
일반적으로 가르쳐주는 "교사"의 존재 여부에 따라 크게 지도 학습과 자율 학습으로 나누어지는데,
"지도 학습 supervised learning"은 교사에 의해 주어진 예제와 정답을 컴퓨터가 제공받는다.
지도학습의 목표는 입력을 출력에 매핑하는 일반적인 규칙을 학습하는 것이다.
그 이후 새로운 입력값이 들어왔을 때, 합리적인 출력값을 예측하는 것이다.
예를 들어 y = 10x 라는 함수가 있고, 컴퓨터는 아직 이 방정식으로 표현할 수 있는 데이터를
모르는 상태라고 가정하자.
(1,10), (2,20), (3,30), (4,40) 의 좌표들을 컴퓨터에게 입력하고
주어진 4개의 데이터를 학습하여 학습이 끝난 후에 x = 5 를 입력하면
컴퓨터가 y = 50 이라는 답을 할 수 있도록 만들고 싶다.
이 경우 입력된 값을 바탕으로 컴퓨터가 스스로 이 입력을 설명할 수 있는
가장 좋은 함수를 찾는 것이 바로 지도학습이며,
이 문제는 지도학습 중에서도 "회귀분석 regression" 이라고 할 수 있다.
그럼 이제 우리는 가장 간단한 회귀라고 볼 수 있는 "선형 회귀 분석" 을 진행해보려고 한다.
파이썬에서 가장 많이 사용되는 기계학습 라이브러리 중 하나인 "사이킷런 scikit-learn" 을 사용하자.
사이킷런은 선형 회귀, k-NN 알고리즘 등 다양한 알고리즘을 포함하고 있어서
기계학습을 처음 접하는 사람들에게 좋은 도구로 인기를 얻고 있다.
선형회귀는 임의의 변수 x, y 의 상관관계를 모델링하는 것이다.
두 변수의 관계를 알아내거나 이를 이용해 y 가 없는 x 값에 대해
y 를 예측하는데 사용할 수 있다.
그렇다면 이제 선형 회귀를 사이킷런을 이용해 구현해보자.
교실에 있는 4명의 학생을 임의로 추출하여 키와 몸무게를 측정했다고 가정하자.
키를 X 변수에, 몸무게를 y 변수에 대입하자.
선형회귀를 위한 데이터 X 는 2차원 리스트에 넣어야 한다.
다음 코드를 살펴보자.
import numpy as np
from sklearn import linear_model # scikit-learn 모듈을 가져온다.
regr = linear_model.LinearRegression()
X = [[164], [179], [162], [170]] # 다중회귀에도 사용하도록 함.
y = [53, 63, 55, 59] # y = f(x) 의 결과
regr.fit(X, y)
주의할 점은 학습 데이터는 여러 변수에 대해서 다중회귀분석을 실시하기 위해서
반드시 2차원 배열이어야 한다는 점이다.
선형 회귀 분석을 적용하려면 fit() 함수에 X와 y를 전달한다.
이제 선형 회귀 학습결과를 확인하고 예측해보자.
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)
input_data = [ [180], [185] ]
학습은 절편과 계수를 결정하는 일이다.
절편과 계수를 확인하고 싶으면 선형회귀 모델이 가지고 있늰 특성값 coef_ 와 intercept_ 를 확인하면 된다.
그리고 이 값들이 입력 X에 대해 y를 예측하는 데에 얼마나 적합한지는
score() 함수를 통해 확인할 수 있다.
위 코드의 결과를 확인해보자.
선형관계에 가까운 데이터를 사용했기 때문에 1에 가까운 0.9 정도의 값을 얻을 수 있다.
이제 이렇게 학습한 데이터를 바탕으로 새로운 입력이 주어지면 그에 맞는 결과를 예측할 수 있다.
값을 예측하는 함수는 predict() 이다.
이 함수의 매개변수는 예측에 필요한 입력 데이터이고,
이 데이터는 선형회귀 학습을 할 때 사용한 입력 X 와 같이 2차원 배열이다.
두 건의 예측을 해보자.
X 의 값이 180인 경우와 185인 경우에 y 의 값은 어떠할 지 예측하는 것이다.
코드는 다음과 같다.
input_data = [ [180], [185] ]
result = regr.predict(input_data)
print(result)
코드의 결과를 살펴보자.
이 선형회귀 모델은 키가 180cm 일 경우 63.71kg,
185cm 일 경우 66.47kg 이라는 예측값을 보여주고 있다.
이제 이 선형회귀 모델을 그래프로 그려보자.
위에서 다룬 코드와 함께 matplotlib 라이브러리를 함께 사용하면 된다.
matplotlib 라이브러리를 이용해 차트를 그리는 것을 모르겠다면 아래 글을 참고하자.
이제 코드를 살펴보겠다.
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()
X, y 값을 산포도 플롯을 이용해 검은색 점으로 화면에 출력한 후
선형회귀 모델을 적용하여 이 직선을 화면에 그려보았다.
아래 결과와 같이 선형회귀 모델이 적용된 직선이 데이터의 분포를
효과적으로 표현하는 것을 볼 수 있다.
위에서 다룬 선형회귀는 사람의 몸무게를 추정하기 위해 키를 사용한다.
하지만 정확도는 아주 떨어질 수 밖에 없다.
예측하기 위해서는 많은 데이터와 특징을 가지는 복잡한 데이터들이 많을수록 정확도는 올라가는데,
예제를 통해서 알아보자.
사이킷런에서는 당뇨병 환자들의 데이터가 기본적으로 포함되어 있다.
이 데이터는 sklearn 의 datasets 라는 모듈의 load_diabetes() 함수를 통해서 가져올 수 있다.
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn import datasets
# 당뇨병 데이터 세트를 sklearn의 데이터집합으로부터 읽어들인다.
diabetes = datasets.load_diabetes()
읽어들인 당뇨 데이터는 diabetes 에 담았다.
이 데이터는 입력으로 사용되는 data, 그리고 학습시 결과값으로 사용되는 target,
그리고 입력이 가진 특징들의 이름을 저장하고 있는 feature_names 등이 담겨있다.
이제 diabetes 데이터 세트의 data 항목의 shape 속성을 통해
당뇨병 데이터 세트의 형태를 출력해보자.
print('shape of diabetes.data: ', diabetes.data.shape)
print(diabetes.data)
위와 같이 442X10 형태임을 알 수 있다.
여기서 442는 행의 개수로 모두 442 개의 데이터가 있다는 뜻이고,
10은 데이터 세트의 특징이 10개가 있다는 의미이다.
이제 입력 데이터가 가지는 특징들의 이름을 출력해보자.
print('입력데이터의 특성들')
print(diabetes.feature_names)
특징은 위와 같이 나이, 성, 체질량 지수, 혈압이 있고, s1 ~ s6 은 당뇨수치에 영향을 줄 수 있는
각종 검사값을 나타낸다.
결과값은 기준일로부터 1년 후 검사자의 당뇨수치 진행도이다.
입력에 따라 얻어야 하는 출력값을 살펴보자.
이것은 diabetes.target 에 저장된다.
총 442개의 데이터를 가지므로 출력은 442의 스칼라 값이 되어야 한다.
따라서 diabetes.target.shape 은 (442,) 가 표시될 것이다.
print('target data y:', diabetes.target.shape)
print(diabetes.target)
이제 우리는 가설을 하나 세워보겠다.
"체질량지수가 높은 사람은 당뇨 수치가 높을 가능성이 있다."
diabetes.data 의 10가지 특징 중에서 체질량 지수 BMI 에 해당하는 세 번째 항목 하나만을
추출하여 입력 데이터로 사용해 보려고 한다.
이를 추출하는 방법은 데이터의 전체 행에 대해 세 번째 열을 가져오는 것이다.
그러나 이 방법은 1차원 배열로 불러올 것이고, 위에서 말했던 바와 같이
선형회귀의 입력 데이터로 쓸 수 없다.
따라서 배열의 차원을 증가시키고 싶을 때는 넘파이의 newaxis 속성을 이용한다.
다음과 같이 코드를 작성하면 (442, 1) 형태의 2차원 배열이 된다.
X = diabetes.data[:, np.newaxis, 2] # 배열의 차원을 증가시킴
print(X) # (442, 1) 형태의 행렬이 되었는가 확인
이제 입력 데이터를 이용해 선형회귀 학습을 진행하자.
과연 체질량지수와 당뇨수치는 어떤 상관관계가 있을까?
이제 학습을 진행하려고 하는데, 학습을 하기에 앞서서 학습을 할 데이터와
테스트를 진행할 데이터를 분리시키자.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(diabetes.data[:, np.newaxis, 2],
diabetes.target,
test_size = 0.2)
학습을 위해서 전체 442 개의 데이터 중 80% 만을 사용해보자.
이를 위해서 sklearn 에서 제공하는 train_test_split() 이라는 함수를 사용하면 된다.
이 함수의 인자로 data와 target이 주어지는데, 이것은 입력 데이터와 출력 데이터이다.
여기서 얼마의 비율을 학습에서 제외하고 테스트에 사용할지를
test_size 매개변수에 지정해준다.
이제 x_train 과 y_train 과 같은 학습용 데이터를 이용하여 선형회귀 모델로 학습을 수행하고,
이제 테스트용 데이터가 학습을 통해 얻은 선형 함수를 얼마나 잘 따르는 지 확인해보자.
regr = linear_model.LinearRegression()
regr.fit(X_train, y_train)
score = regr.score(X_train, y_train)
print(score)
score = regr.score(X_test, y_test)
print(score)
결과를 확인해보자.
선형회귀 학습을 마치고 학습용 데이터는 찾아낸 선형함수를 따르는 정도가 0.330 정도이고,
테스트용 데이터는 0.385 정도가 나오고 있는 것을 확인할 수 있다.
이제 우리는 예측한 결과와 실제 데이터를 비교해보자.
학습용으로 80%의 데이터를 사용하고, 테스트용으로 20% 의 데이터를 이용해 예측해보자.
이렇게 예측한 결과를 matplotlib 을 이용해 산포도 그래프로 표현하려 한다.
전체 코드는 다음과 같다.
import numpy as np
from sklearn import linear_model # scikit-learn 모듈을 가져온다
from sklearn import datasets
import matplotlib.pyplot as plt
diabetes = datasets.load_diabetes()
regr = linear_model.LinearRegression()
# 학습 데이터와 테스트 데이터를 분리한다.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(diabetes.data,
diabetes.target,
test_size=0.2)
regr.fit(X_train, y_train)
print(regr.coef_, regr.intercept_)
y_pred = regr.predict(X_test)
plt.scatter(y_pred, y_test)
plt.show()
지금까지 우리는 지도학습에서도 아주 간단한 선형 회귀 분석에 대해 공부를 해보았다.
다른 어떤 분야도 마찬가지겠지만, 기계학습에는 다양한 알고리즘이 존재하고
데이터를 어떻게 이용하고, 알고리즘을 어떻게 짜느냐에 따라 결과가 다를 수 있다.
나올 수 있는 오차를 잘 인지하고 학습을 적절하게 만들수록 좋은 분석을 할 수 있을 것이다.
다음 시간에는 tensorflow 를 이용하여 딥러닝을 살짝 맛보도록 하자.
출처 : 따라하며 배우는 파이썬과 데이터 과학 - 천인국, 박동규, 강영민