티스토리 뷰
선형회귀 (Linear Regression)¶
- 회귀는 데이터가 주어졌을 때, 실수값인 타겟값(또는 목표값)을 예측하는 방법이다.
나이 | 성별 | 키 | 몸무계 |
---|---|---|---|
35 | 남 | 175 | 67 |
... | ... | ... | ... |
27 | 여 | 163 | 52 |
- 위와 같은 데이터가 주어졌을 때, 키(데이터)에 따른 몸무계(타겟값)를 예측하는 것은 회귀 문제이다.
- 회귀 중에서도, 직선 또는 곧은 평면(굽은 평면이 아님)으로 타겟값을 예측하는 것을 선형회귀 라고 한다. 아래 그림에서 직선으로 예측한 경우에 해당한다.
- 속성이 하나 뿐일 때는 위와 같이 직선으로 표현할 수 있지만 속성이 2개일 때는 곧은 평면, 3개 이상에서는 초평면으로 표현한다.
- 선형회귀에서 굳이 타겟값을 별도로 구분했지만, 다르게 표현하면 타겟값을 포함한 모든 속성의 상관관계를 평면으로 표현한 것으로 이해할 수 있다.
- 아래에서 Iris 데이터를 가지고 선형회귀를 적용해 보겠다.
In [2]:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data[:,:3]
y = iris.data[:,3]
In [3]:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y)
In [4]:
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X_train, y_train)
Out[4]:
In [5]:
model.score(X_test, y_test)
Out[5]:
In [6]:
pred_y = model.predict(X_test)
display(pred_y[:10], y_test[:10])
In [7]:
model.coef_ # 속성이 3개이므로 기울기 3개
Out[7]:
In [8]:
model.intercept_ # y절편
Out[8]:
u = ax + by + cz + d¶
w0+w1x1+w2x2+w3x3+w4x4=0
In [10]:
배가 너무 고프다. 너무너무 고프다. 죽을 거 같다.
In [63]:
import pandas as pd
# 산점도를 한번에 그리는 방법
iris_df = pd.DataFrame(iris.data, columns=iris.feature_names)
pd.plotting.scatter_matrix(iris_df, c=y, s=60, alpha=0.8, figsize=[12,12])
Out[63]:
In [34]:
fig = plt.figure(figsize=[12,8])
fig.suptitle('Iris\n(setosa:0, versicolor:1, virginica:2)', fontsize=20)
count=0
for i in range(3):
for j in range(i+1, 4):
count+=1
plt.subplot(2,3,count)
plt.scatter(iris.data[:,i],iris.data[:,j],c=iris.target,s=60,alpha=0.5)
plt.xlabel(iris.feature_names[i])
plt.ylabel(iris.feature_names[j])
plt.colorbar(shrink=0.7)
Out[34]:
(150,) >(150,1)로 reshape [ 1,2,3,4 ] > [[1],[2],[3],[4]] 형태로 변경
In [74]:
X = iris.data[:,0]
X
Out[74]:
In [75]:
X.shape
X
display(X.shape,X)
X는 2차원 어레이 형태여야 한다.¶
In [77]:
X.reshape(150,1)[:10] # X.reshape(-1,1) , iris.data[:,[0]]
Out[77]:
In [78]:
iris.data[:,[2,3]][:10] #iris.data[:,2:4]
Out[78]:
In [35]:
X = iris.data[:,[0]]
y = iris.data[:,1]
In [36]:
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X, y)
w = model.coef_[0] # 기울기
b = model.intercept_ # y 절편
print('score =', model.score(X,y))
print('w =', w)
print('b =', b)
1번 컬럼과 2번 컬럼의 산점도를 보면 흩뿌려져 있다. 그래서 0에 가깝게 나왔다.
In [37]:
model.coef_ # 결과는 Numpy 어레이 이다.
Out[37]:
In [38]:
X = iris.data[:,[0]]
y = iris.data[:,2]
In [39]:
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X, y)
w = model.coef_[0] # 기울기
b = model.intercept_ # y 절편
print('score =', model.score(X,y))
print('w =', w)
print('b =', b)
1번 컬럼과 3번 컬럼의 산점도를 보면 일직선에 많이 놓여있다. 기울기가 1처럼 보일 수 있겠지만 X축과 y축 폭이 달라 실제로는 2에 가까운 기울기를 갖고 있다.
In [44]:
fig=plt.figure(figsize=(6,10))
plt.title('Linear Regression\n(petal_length vs petal_width)')
plt.scatter(X,y,c=iris.target,s=60)
plt.xlabel(iris.feature_names[0])
plt.ylabel(iris.feature_names[2])
plt.colorbar()
plt.plot([4,8],[4*w+b,8*w+b],'y',lw=10,alpha=0.5)
# 끝값 4과 8은 직접 그래프를 보고 정한 값. 좌표가 (4,4*w+b), (8,8*w+b)
plt.text(0,3,'coef: %f\nintercept: %f' % (w,b), va='top', fontsize=15,color='b') # %3f 라고 하면 소수점 3개까지 나옴
plt.axis('equal')
plt.grid()
모든 머신러닝 알고리즘은 오차값(비용함수)을 정의하고 오차값을 최소화하게 한다. 대표적으로 최소 제곱법(MSE, mean squared error)을 사용
In [47]:
result = model.predict([[5],[6],[7]])
display(result, 5*w+b, 6*w+b, 7*w+b)
In [54]:
model.predict(X)[:10]
Out[54]:
In [55]:
y[:10]
Out[55]:
In [56]:
score = model.score(X,y)
display(score) #R^2 값
- 회귀에서의 평가 점수는 $R^2$ 이라는 것을 사용한다.
$R^2 = 1 - \frac{\sum (y-\hat{y})^2} {\sum (y-\bar{y})^2} $ ($\bar{y}$ 는 평균, $\hat{y}$ 는 예측값)
$R^2$ 값이 1 이면 완벽하게 예측했다는 의미이고, 0 이면 누구나 하듯이 평균값으로 에측했다는 의미이다. 그리고 음수이면 평균값 예측보다도 못하다는 의미가 된다.
- 앞에서 model.fit() 을 하고 나면, model.coef_ 으로 기울기 값을 model.intercept_ 로 y절편 값을 얻을 수 있다.
- 그런데 앞의 예제는 앞에서 중요하게 강조했던 학습세트와 테스트세트로 분리하지 않았다. 그냥 전체 데이터를 사용하여 두 속성의 상관관계 만을 알고 싶었기 때문이다.
- 하지만 제대로 머신러닝 과정을 밟기 위해 아래에서 학습세트와 테스트세트로 분리하여 적용해 보자. 이렇게 하면 여러가지 예측모델 중에서 어떤 예측모델이 더 나은지 판단할 수 있게 된다.
In [86]:
from sklearn.model_selection import train_test_split
X = iris.data[:,0].reshape(-1,1) # reshape() 함수에 주의
y = iris.data[:,2]
X_train,X_test,y_train,y_test = train_test_split(X, y)
model = LinearRegression()
model.fit(X_train, y_train)
w = model.coef_[0] # 기울기
b = model.intercept_ # y 절편
print('w =',w)
print('b =',b)
In [87]:
score1 = model.score(X_train, y_train)
score2 = model.score(X_test, y_test)
display('학습세트 점수: %f' % score1, '테스트세트 점수: %f' % score2) # R^2 값
- 결과에서 보듯이 테스트세트에 대한 $R^2$ 값이 학습세트에 대한 값 보다 못한 결과를 얻었다.
- 이것은 당연한데, 학습에 사용하지 않은 데이터로 테스트를 했기 때문이다.
- 이제 다른 방법으로 학습 결과를 평가해 보자.
- RMSE(root-mean-square error) = $\sqrt{\frac{(y-\hat{y})^2} {N} }$ , (RMSE 는 값이 작을 수록 결과가 좋은 것이다.)
- 선형회귀의 수학적 원리는 RMSE 를 최소화 하는 초평면을 찾는 것이다.
In [88]:
pred_y = model.predict(X_test)
pred_y
Out[88]:
In [89]:
y_test
Out[89]:
In [96]:
MSE = ((y_test - pred_y)**2).sum()/len(y_test)
MSE
Out[96]:
In [98]:
RMSE = np.sqrt(MSE)
RMSE
Out[98]:
- 이제 타겟값인 petal_width 를 제외한 나머지 세가지 속성을 모두 사용하여 선형회귀를 적용해 보자.
- 이럴 경우, 4차원 상에 3차원 초평면으로 예측하기 때문에 그림으로 결과를 표현하기는 쉽지 않다.
속성 3개¶
In [99]:
X = iris.data[:,:3]
y = iris.data[:,3]
X_train,X_test,y_train,y_test = train_test_split(X, y)
model = LinearRegression()
model.fit(X_train, y_train)
w = model.coef_ # 기울기 (데이터의 속성이 3개이므로 값이 3개임), 1번 4번, 2번 4번, 3번 4번
b = model.intercept_ # y 절편
print('w =',w)
print('b =',b)
In [100]:
score1 = model.score(X_train, y_train)
score2 = model.score(X_test, y_test)
display('학습세트 점수: %f' % score1, '테스트세트 점수: %f' % score2) # R^2 값
In [101]:
pred_y = model.predict(X_test)
pred_y
Out[101]:
In [102]:
y_test
Out[102]:
In [103]:
MSE = ((y_test - pred_y)**2).sum()/len(y_test)
MSE
Out[103]:
In [104]:
RMSE = np.sqrt(MSE)
RMSE
Out[104]:
In [107]:
MAE = np.abs(y_test - pred_y).sum()/len(y_test)
MAE
Out[107]:
속성이 3개이므로 w 의 값은 3개이다.
$pred\_y = w_1 \cdot x_1 + w_2 \cdot x_2 + w_3 \cdot x_3 + b$
train_test_split() 함수를 호출할 때 마다 훈련세트/테스트세트 가 새롭게 구성되므로 score 가 달라질 수 있고 학습 보다 테스트 시 더 score 가 높은 경우도 있다.
- 다양한 선형회귀 모델은 다음 URL 을 참고하자. (http://scikit-learn.org/stable/modules/linear_model.html)
- 선형회귀의 변종인 릿지회귀와 라쏘회귀는 뒤에서 다룬다.
- 2차곡선, 3차곡선 과 같이 다항식을 적용한 다항회귀도 있다. (위 URL의 1.1.16 참고)
In [93]:
x = [[1,2,3],[2,2,4]]
model.predict(x)
Out[93]:
In [94]:
model.coef_[0]*1 + model.coef_[1]*2 + model.coef_[2]*3 + model.intercept_
# [1,2,3] 샘플에 대한 예측값 직접 계산
Out[94]:
- 선형회귀에서 사용하는 선형 알고리즘은 다른 많은 머신러닝 알고리즘의 기반이 된다.
- 특히 신경망의 핵심 알고리즘은 선형회귀에서 나온 것이며, 가장 간단한 신경망은 곧 선형회귀와 같다.
'beginner > 파이썬 머신러닝 기초' 카테고리의 다른 글
지도학습 - LinearSVM_1 (0) | 2019.03.05 |
---|---|
1월 지하철 승하차 인원 분석 (0) | 2019.02.28 |
와인 데이터 분석 (0) | 2019.02.26 |
sklearn 기본 틀 (0) | 2019.02.26 |
Numpy를 활용한 수치근사법 (0) | 2019.02.25 |