본문 바로가기
  • 조금 느려도, 꾸준히
Artificial Intelligence/Machine Learning

핸즈온 머신러닝(5) - 다항 회귀

by chan 2020. 1. 23.
반응형

# 다항 회귀

데이터가 단순한 직선의 형태가 아닌 비선형 형태여도, 선형 모델을 사용하여 비선형 데이터를 학습할 수 있다.

이때 각 특성의 거듭제곱을 새로운 특성으로 추가하고, 확장된 특성을 포함한 데이터셋에 선형 모델을 훈련시키는 것인데, 이러한 기법을 다항 회귀(Polynomial Regression) 이라고 한다.

 

실습하기 위해 먼저 노이즈를 포함한 간단한 2차 방정식으로 비선형 데이터를 생성해 보도록 한다.

import numpy as np
import numpy.random as rnd

rnd.seed(42)
m = 100
X = 6 * rnd.rand(m, 1) - 3
y = 0.5 * X**2 + X + 2 + rnd.randn(m, 1)

$y = 0.5x^2 + x + 2 + noise$ 함수로 데이터셋을 만들었다. 

사이킷런의 PolynomialFeatures 를 사용하여 훈련 세트에 있는 각 특성을 제곱하여 새로운 특성으로 추가한 훈련 데이터를 만들어 보면 다음과 같다.

 

from sklearn.preprocessing import PolynomialFeatures
poly_features = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly_features.fit_transform(X)

 

이렇게 되면 새로 만들어진 X_poly 라는 데이터셋에는 기존의 X특성 데이터와 특성을 제곱한 데이터가 포함된다. 

즉 예측 모델은 선형 모델이지만 $\theta = ( \theta_0 \: \theta_1 \: \theta_2)$ 이며 각각 bias, $x$의 가중치, $x^2$의 가중치가 되므로 예측값 $\hat{y} = \theta_0 + \theta_1 x + \theta_2 x^2$ 가 되어 선형모델은 2차 함수로 만들어진 데이터셋을 예측할 수 있게 된다.

 

이제 확장된 훈련 데이터에 LinearRegression을 적용해 보면 다음과 같다.

 

lin_reg = LinearRegression()
lin_reg.fit(X_poly, y)
lin_reg.intercept_, lin_reg.coef_
# (array([1.78134581]), array([[0.93366893, 0.56456263]]))


"""
그래프 출력
"""
X_new=np.linspace(-3, 3, 100).reshape(100, 1)
X_new_poly = poly_features.transform(X_new)
y_new = lin_reg.predict(X_new_poly)
plt.plot(X, y, "b.")
plt.plot(X_new, y_new, "r-", linewidth=2, label="predict")
plt.xlabel("$x_1$", fontsize=18)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.legend(loc="upper left", fontsize=14)
plt.axis([-3, 3, 0, 10])
plt.show()

 예측된 모델은 $\hat{y} = 1.78 + 0.93 x_1 + 0.56 x_1^2$ 이며 그래프는 다음과 같다

 

 

 

PolynomialFeatures 는 주어진 차수까지 특성 간의 모든 교차항을 추가하기 때문에 특성 간의 관계를 찾을 수 있다. 예를 들어 특성 $a,b$ 에 대하여 degree=3 으로 PolynomialFeatures를 적용하면 $a^2, a^3, b^2, b^3, ab, a^2b, ab^2$ 을 특성으로 추가한다. 만약 interaction_only = True 로 지정하면 $ab$만이 새로운 특성으로 추가된다. PolynomialFeatures.get_feature_names() 메서드를 이용해 만들어진 특성의 차수를 확인할 수 있다.

 

poly_features.get_feature_names()

# ['x0', 'x0^2']

 

반응형

댓글