brunch

[R vs. Python]회귀분석

1차 선형, 2차 선형 회귀

by 첨물

사실 머신러닝의 기본은 선형 회귀분석이다.

여러 마리의 농어의 길이와 무게가 있다고 하자. 길이 얼마일 때, 무게가 얼마일지 알아맞히는 것이다.


먼저 파이썬으로 1차 선형 회귀를 한 후, R로 재현해 보고 2차 선형 회귀로 반복해 보도록 하겠다.


1-P. 파이썬으로 하는 1차 선형 회귀


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을 불러와야 한다. 길이가 증가할수록 무게는 증가하는 것으로 나왔다.

Clipboard04.jpg

그럼 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에 무게를 예측한 점을 그래프에 표시해 보자.

Clipboard06.jpg


마지막으로 파이썬에만 있는 score 함수를 이용하여 test_x, test_y를 이 모델에 넣었을 경우, 얼마나 잘 맞았는지 확인할 수 있다.


print(lr.score(test_x, test_y))

0.8247503123313558



1-R. R로 하는 1차 선형 회귀


R은 파이썬처럼 뭘 하려고 할 때 기본 내장 패키지가 있으므로 간단하게 할 수 있다.


일단 R의 장점인 dataframe으로 농어의 길이와 무게를 묶어 놓고 시작하자.


df<-as.data.frame(cbind(perch_length, perch_weight))


이걸 그래프로 그려보는 것도 간단히 한 줄로...

화면 캡처 2021-09-10 163623.jpg

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에 해당하는 것을 예측해서 점으로 표시해보자.

화면 캡처 2021-09-10 164107.jpg

R에서는 따로 test를 1차 회귀식 모델로 예측하여 얼마나 잘 맞는지 확인하는 함수는 없지만, 아래와 같이 test 원래 데이터와 train으로 모델링한 1차 회귀식을 예측한 값을 그래프로 표현할 수 있다.

화면 캡처 2021-09-10 164641.jpg

점들과 회귀 선이 얼마나 잘 맞는지는 R-square로 알 수 있다.

화면 캡처 2021-09-10 164744.jpg

2-P. 파이썬으로 하는 다항 회귀


농어의 길이와 무게 그래프는 아무래도 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()

화면 캡처 2021-09-11 231455.jpg


마지막으로 파이썬의 score() 함수를 써서 얼마나 잘 예측했는지 보자.


print(lr.score(train_poly, train_y))

print(lr.score(test_poly, test_y))

0.9706807451768623

0.9775935108325122


3-R. R로 하는 다항 회귀


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)

화면 캡처 2021-09-11 233546.jpg

R에서는 파이썬의 score() 함수 대신 R_square 값을 통해 추세선이 얼마나 잘 예측했는지 알 수 있다.

화면 캡처 2021-09-11 233739.jpg

[파이썬을 이용한 선형 회귀]

https://colab.research.google.com/drive/1I7VsPxyF92GVmHw_IxUcSB99x-XpQork?usp=sharing

[R을 이용한 선형 회귀]

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


keyword
매거진의 이전글[R vs.Python] 다중회귀분석