본문 바로가기
내가 하는 데이터분석/내가 하는 머신러닝

[다항 회귀, Polynomial Regression] with Python

by Pymoon 2023. 1. 30.

 

이 전의 머신러닝에서는 단순 선형 회귀(Simple Linear Regression Model)에 대해서 다뤄보았다.

 

단순 선형 회귀(Simple Linear Regression Model) with Python

머신러닝 기법 중 단순 선형 회귀모델에 대해 다뤄보며 정리하고자 한다. 선형 회귀는 입력(하나의 독립변수)에 대한 선형함수를 만들어 미래를 예측하는 알고리즘이다. 예를 들어, 나이에 따른

py-moon.tistory.com

 

 

데이터가 단순 선형 회귀 때처럼 단순한 직선 형태가 아닌 비선형의 형태를 갖고 있을 때, 각 변수의 거듭제곱을 새로운 변수로 추가하면 선형 모델을 사용할 수 있다.

이렇게 확장된 특성을 데이터셋에 선형 보델로 훈련시키는 기법인 다항 회귀(Polynomial Regression)를 다뤄보며 정리해 보자.

 

 

단순 선형 회귀와 다항 회귀의 차이점은 독립변수나 종속변수의 개수차이가 아니다.

차이점을 간단하게 말하자면, 단순 선형 회귀식이 1차식으로 인해 회귀선이 직선이었다.

하지만, 다항 회귀식은 2차 이상으로 이루어짐에 따라 회귀선이 곡선으로 이루어져 있다는 점이다.

 

데이터를 직접 다뤄보면서 다항 회귀를 구현해 보자.

 

 

 


 

다항 회귀에 대한 실습은 cereal데이터를 활용해서 구현하고자 한다.

 

1
2
3
4
5
6
7
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings(action='ignore')
 
 
cereal = pd.read_csv('data/cereal.csv')
cs

 

> 먼저, 모델 구현을 위해 필요한 라이브러리와 데이터를 불러와준다.

 

> 나의 코드에서 자주 등장하는 부분인 warnings는 시각화를 할 때 괜히 거슬리는 경고창이 뜨지 않고 무시할 수 있도록 해주는 코드로 유용하게 쓰고 있다.

 

 

 

cereal.head()

> 상위 5개의 데이터를 확인하면서 데이터 현황을 대략적으로 파악한다.

 

> 분석에 필요한 데이터만을 추출하기 위해 약간의 전처리를 진행한다.

 

 

 

 

1
2
cereal = cereal.drop(['name''mfr''type'], axis = 1)
cereal = cereal[cereal.sugars >= 0]
cs

 

> 우선, object형의 자료형을 가지는 변수들을 제거해 준다. 그리고 모델 구현에서 독립변수로 사용될 sugars(설탕 함유량) 변수에서 음수는 제거한 데이터만을 추출해 준다.

 

 

 

 

1
2
3
data = cereal[['sugars''rating']]
data.sort_values(by = ['sugars'], inplace = True)
data.reset_index(drop = True, inplace = True)
cs

 

> 독립변수sugar(설탕 함유량) 변수와 종속변수rating(영양 등급 평가) 변수를 data라는 데이터프레임에 따로 할당해 준다.

 

> 그리곤 sugar 변수를 기준으로 오름차순으로 데이터를 정렬해 주고, 뒤섞여있는 index도 초기화해주면서 데이터를 이쁘게 만들어준다.

 

> 여기서, inplace = True 부분은 변수를 따로 할당하지 않아도 해당 데이터프레임에 적용될 수 있게 하는 파라미터이다.

 

 

 

data.head()

> 위에서 나열한 전처리를 진행한 결과인 데이터이다.

 

> 분석에 필요한 데이터인 독립변수와 종속변수만 있는 모습을 볼 수 있다.

 

 

 

sugars와 rating 사이의 산점도

> 정제한 데이터를 산점도를 통해서 두 변수 간의 관계를 확인한다.

 

> 대략적인 직관으로는 설탕함유량이 낮을수록 영양 등급이 높은 편이고, 설탕함유량이 많을수록 영양 등급이 낮다는 것을 알 수 있다.

 

 

 

 

1
2
3
4
5
6
7
from sklearn.model_selection import train_test_split
 
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size = 0.3, random_state = 1)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
 
 
(53,) (23,) (53,) (23,)
cs

 

> 모델 학습을 위해 데이터셋을 분리해 주는 과정을 진행한다.

 

> train_test_split()을 활용해서 총 4가지로 분리해 준다.

 

 

 

 

1
2
3
4
from sklearn.preprocessing import PolynomialFeatures
 
poly_reg = PolynomialFeatures(degree = 2)
X_poly = poly_reg.fit_transform(X_train.reshape(-11))
cs

 

> 그리곤 변수의 특성을 확장시키기 위해 거듭제곱으로 변환해 줄 PolynomialFeatures를 활용한다.

 

> 이 경우, degree = 2로 했기 때문에 2차 항으로 데이터를 변환해 준다.

 

> 이를 통해서 일반적인 선형 회귀 모델과 달리 변수들 사이의 관계를 찾을 수 있는 다항 회귀의 장점을 활용할 수 있는 것이다.

 

 

 

 

1
2
3
4
from sklearn.linear_model import LinearRegression
 
reg = LinearRegression()
reg.fit(X_poly, y_train)
cs

 

> 변환된 데이터를 회귀모델에 학습시킨다.

 

 

 

 

1
2
3
4
5
6
import numpy as np
 
X_test_poly = poly_reg.transform(X_test.reshape(-11))
pred = reg.predict(X_test_poly)
 
np.set_printoptions(precision = 2)
cs

 

> 다항 회귀 모델을 평가하기 위해 test데이터셋도 변환해 주고, 예측치까지 추출해 준다.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
from sklearn.metrics import mean_squared_error, mean_absolute_error, mean_squared_error
 
print('MSE :', round(mean_squared_error(y_test, pred), 2))
print('MAE :', round(mean_absolute_error(y_test, pred), 2))
print('RMSE :', round(np.sqrt(mean_squared_error(y_test, pred)), 2))
print('Accuracy : {:.2f}%'.format(reg.score(poly_reg.transform(X_test.reshape(-11)), y_test)*100))
 
 
MSE : 33.57
MAE : 4.61
RMSE : 5.79
Accuracy : 74.38%
cs

 

> 지금까지 구축한 모델에 대한 성능을 회귀분석에서 사용하는 지표를 통해서 평가해 본다.

 

 

 

산점도 with 회귀선

> 학습된 모델에 대한 회귀식을 원본 데이터 산점도와 비교해 나타내었다.

 

> 시각 자료로 보았을 땐 성능지표완 다르게 다항 회귀 모델이 괜찮은 예측력을 가지고 있는 듯해 보인다.

 

 

 


 

이번에는 독립변수가 12개인 원본 데이터셋(object자료형은 제외)을 활용해서 고차 다항 회귀 모델을 구축해 보자.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
= cereal.iloc[:, :-1].values
= cereal.iloc[:, -1].values
 
from sklearn.model_selection import train_test_split
 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 1)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
 
 
(5312) (2312) (53,) (23,)
cs

 

> 마찬가지로 데이터 분할을 진행하지만 분할된 데이터의 shape을 보니 차이를 확인할 수 있다.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from sklearn.preprocessing import StandardScaler
 
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
 
 
from sklearn.preprocessing import PolynomialFeatures
 
poly_reg = PolynomialFeatures(degree = 2)
X_poly = poly_reg.fit_transform(X_train)
 
 
from sklearn.linear_model import LinearRegression
 
reg = LinearRegression()
reg.fit(X_poly, y_train)
cs

 

> 이번에는 모든 데이터를 활용했기 때문에 그 분포에 대한 데이터의 스케일링이 필요하여 StandardScaler를 활용해서 데이터의 정규화를 진행해 준다.

 

> 그리곤 위에서 했었던 차수를 올리는 과정과 모델을 학습시키는 과정을 동일하게 진행해 준다.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np
 
X_test_poly = poly_reg.transform(X_test)
pred = reg.predict(X_test_poly)
 
 
from sklearn.metrics import mean_squared_error, mean_absolute_error, mean_squared_error
 
print('MSE :', round(mean_squared_error(y_test, pred), 2))
print('MAE :', round(mean_absolute_error(y_test, pred), 2))
print('RMSE :', round(np.sqrt(mean_squared_error(y_test, pred)), 2))
print('Accuracy : {:.2f}%'.format(reg.score(poly_reg.transform(X_test), y_test)*100))
 
 
MSE : 9.54
MAE : 2.12
RMSE : 3.09
Accuracy : 92.68%
cs

 

> 그리곤, 똑같이 회귀분석에서 사용하는 성능평가지표를 활용해서 모델을 평가해 보았다.

 

> 성능이 확실히 좋아진 것을 확인할 수 있다. 오차를 나타내는 MSE, RMSE, MAE도 낮아지고, 정확도는 올라간 결과이다.

 

 


 

OUTTRO.

 

 

다항 회귀와 고차 다항 회귀를 순서대로 진행해 보았다.

 

결과에서 확인했듯이 고차 다항 회귀가 압도적으로 성능이 좋은 것을 확인할 수 있었다.

 

두 모델의 차이점으로는 독립변수가 1개였느냐, 12개였느냐이다.

 

나의 견해로는 종속변수인 영양등급평가를 설명하기에는 1개의 변수로는 아무리 그 특성을 확장한다 하더라고 한계가 있었지 않았나 하는 생각이 든다.

 

그렇기에 차이가 꽤 있는 성능을 보여준 것이라고 생각한다.

 

 

하지만, 너무 많은 독립변수를 사용하게 되면 다중공선성 문제와 더불어 과대적합에 이를 수도 있기에 조심해서 판단해야 한다.