1차 선형, 2차 선형 회귀
사실 머신러닝의 기본은 선형 회귀분석이다.
여러 마리의 농어의 길이와 무게가 있다고 하자. 길이 얼마일 때, 무게가 얼마일지 알아맞히는 것이다.
먼저 파이썬으로 1차 선형 회귀를 한 후, R로 재현해 보고 2차 선형 회귀로 반복해 보도록 하겠다.
import numpy as np
perch_length = np.array([8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0, 21.0,
21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5, 22.5, 22.7,
23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5, 27.3, 27.5, 27.5,
27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0, 36.5, 36.0, 37.0, 37.0,
39.0, 39.0, 39.0, 40.0, 40.0, 40.0, 40.0, 42.0, 43.0, 43.0, 43.5,
44.0])
perch_weight = np.array([5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0, 110.0,
115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0, 130.0,
150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0, 197.0,
218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0, 514.0,
556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0, 820.0,
850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0, 1000.0,
1000.0])
이와 같은 길이와 무게 데이터가 있을 때 먼저 해 볼 것은 그래프로 그려보는 것이다.
파이썬에서는 배열을 만들 때는 numpy, 그래프를 그릴 때는 matplotlib을 불러와야 한다. 길이가 증가할수록 무게는 증가하는 것으로 나왔다.
그럼 train와 test로 데이터를 나눈 후, 1차 회귀분석을 해 보자
파이썬에서 train, test를 0.75:0.25로 나누려면 (기본) train_test_split을 불러와야 한다.
from sklearn.model_selection import train_test_split
train_x, test_x, train_y, test_y = train_test_split(perch_length, perch_weight, random_state=42)
그리고 나서 회귀 분석을 하려면 가로로 된 train_x, test_x를 세로로 2열이 되도록 만들어주어야 한다.
이것은 R에서도 dataframe으로 만들어 주는 것과 같다.
train_x=train_x.reshape(-1,1)
test_x=test_x.reshape(-1,1)
다음은 1차 회귀 분석을 위해 LinearRegression을 불러온 후 linear model을 만든다. (lr)
from sklearn.linear_model import LinearRegression
lr=LinearRegression()
다음은 이 모델을 이용하여 train_x와 train_y로 학습을 시킨다.
lr.fit(train_x, train_y)
1차 함수의 기울기와 y 절편은 아래와 같이 구할 수 있다.
print(lr.coef_, lr.intercept_)
같은 모델로 길이 50인 농어의 무게를 예측하려면 predict 함수를 사용한다.
print(lr.predict([[50]]))
그러면 train_x, train_y로 그래프를 그린 후, 위에서 찾아낸 1차 함수의 기울기와 y 절편으로 직선을 그려본 후, 길이 50에 무게를 예측한 점을 그래프에 표시해 보자.
마지막으로 파이썬에만 있는 score 함수를 이용하여 test_x, test_y를 이 모델에 넣었을 경우, 얼마나 잘 맞았는지 확인할 수 있다.
print(lr.score(test_x, test_y))
0.8247503123313558
R은 파이썬처럼 뭘 하려고 할 때 기본 내장 패키지가 있으므로 간단하게 할 수 있다.
일단 R의 장점인 dataframe으로 농어의 길이와 무게를 묶어 놓고 시작하자.
df<-as.data.frame(cbind(perch_length, perch_weight))
이걸 그래프로 그려보는 것도 간단히 한 줄로...
R에서는 파이썬과 같이 train, test를 나누는 패키지가 없고, sample 함수를 이용하여 random으로 전체 행의 0.75 만큼 숫자를 뽑은 후 df에 index를 넣어 나누어 준다.
idx<-sample(1:nrow(df), nrow(df)*0.75, replace=F)
train<-df[idx,]
test<- df[-idx,]
다음으로 train 데이터로 1차 함수 회귀식을 만들어 보자.
perch_lm<-lm(y~ x, train )
그럼 파이썬과 같이 train 데이터를 점으로 표시하고, 1차 회귀식을 선으로, 그리고 길이 50에 해당하는 것을 예측해서 점으로 표시해보자.
R에서는 따로 test를 1차 회귀식 모델로 예측하여 얼마나 잘 맞는지 확인하는 함수는 없지만, 아래와 같이 test 원래 데이터와 train으로 모델링한 1차 회귀식을 예측한 값을 그래프로 표현할 수 있다.
점들과 회귀 선이 얼마나 잘 맞는지는 R-square로 알 수 있다.
농어의 길이와 무게 그래프는 아무래도 1차 회귀식으로는 한계가 있다. 따라서 2차 항으로 회귀분석을 다시 해 보기로 한다. 그리고 길이 50에 해당하는 무게를 다시 예측해보기로 하자.
그럼 train_x와 test_x를 1열이 아닌 2열로 만들어서 새로운 train_poly, test_poly 변수를 만들자. 기존 1열이 무게만 있다고 하면 여기에 무게의 제곱을 또 다른 열로 만들어보자. 파이썬에서 기존 열에 추가하는 것은 np.column_stack (x**2, x)이다.
train_p=np.column_stack((train_x**2, train_x))
test_p=np.column_stack((test_x**2, test_x))
그리고 나서 이 두항을 이용하여 y값을 학습시켜보자.
lr=LinearRegression()
lr.fit(train_p, train_y)
그러면 2차 항 계수와 1차 항 계수, y절편을 구할 수 있다.
print(lr.coef_, lr.intercept_)
[ 1.01433211 -21.55792498] 116.05021078278276
이렇게 학습된 모델로 길이 50을 넣어 무게를 예측해보면 1차 회귀식과 다른 값을 얻을 수 있다.
소수점을 반올림하는 np.around() 함수를 써서 값을 구했다.
print(np.around(lr.predict([[50**2, 50]])))
[1574.]
마지막으로 train_p로 예측한 2차 함수를 추세선으로 그려보고 (blue), test_x를 넣었을 때 원래 값인 test_y(red) 와 test_p로 예측한 값(green)이 얼마나 차이가 있는지 산점도로 표시한 후, , 길이 50인 농어의 무게 1574도 점을 찍어보자.
point=np.arange(15,50)
plt.plot(point, 1.01*point**2-21.6*point+116.05, c="blue")
plt.scatter(test_x, test_y, c="red")
plt.scatter(test_x, pre, c="green")
plt.scatter(50,1574, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()
마지막으로 파이썬의 score() 함수를 써서 얼마나 잘 예측했는지 보자.
print(lr.score(train_poly, train_y))
print(lr.score(test_poly, test_y))
0.9706807451768623
0.9775935108325122
R은 x, y를 묶은 dataframe으로 시작하므로 새로운 제곱항이 들어있는 train_p, test_p를 만드는 것에서 시작해보자. 각 열의 이름을 x2, x, y로 만든다.
train_p<-cbind((train$x)^2, train$x, train$y)
test_p<-cbind(test$x^2, test$x, test$y)
train_p<-as.data.frame(train_p)
test_p<-as.data.frame(test_p)
colnames(train_p)<-c("x2", "x", "y")
colnames(test_p)<-c("x2", "x", "y")
다음으로 이 train_p의 x^2과 x 항을 이용하여 y 값을 학습해보자. 그리고 이렇게 학습한 모델로 test_p 를 넣어 y를 예측한 것을 pre에 넣고, 길이 50에 해당하는 무게 값을 pre_50에 넣는다. 무게가 1567로 나왔다.
perch_lm_p<-lm(y~ x2+x, train_p )
pre<-predict.lm(perch_lm_p, test_p, interval = "none")
pre_50<-predict(perch_lm_p, newdata = data.frame(x2=50^2, x=50))
print(round(pre_50))
1567
R에서 2차 항의 계수와 1차 항의 계수, y절편은 아래와 같이 구한다.
print(perch_lm_p)
Call:
lm(formula = y ~ x2 + x, data = train_p)
Coefficients:
(Intercept) x2 x
110.658 1.003 -21.012
그럼 그래프로 그려보자. test의 x, y로 점을 찍고 (red), 2차 회귀로 예측한 값을 점을 찍는다. (green), train으로 예측한 추세선을 그린 후 (blue), 길이 50에 해당하는 무게 점을 찍는다. (brown)
point=c(15:50)
plot(y ~ x , test, col="red", xlim=c(10,50), ylim=c(0,1600), xlab = "length", ylab = "weight",cex=2, pch=16)
points(test$x, pre, col="green",cex=2, pch=16)
lines( 1.0 *point^2 - 21.0*point+110.6 ~ point , col="blue")
points(50, pre_50, col="brown", pch=17, cex=2)
R에서는 파이썬의 score() 함수 대신 R_square 값을 통해 추세선이 얼마나 잘 예측했는지 알 수 있다.
[파이썬을 이용한 선형 회귀]
https://colab.research.google.com/drive/1I7VsPxyF92GVmHw_IxUcSB99x-XpQork?usp=sharing
[R을 이용한 선형 회귀]
https://colab.research.google.com/drive/1Eo3ndusQ5iK8tpbUPLCngzEQYKyw_dyk?usp=sharing