여러 개의 특성을 사용한 선형 회귀를 다중 회귀라고 한다.
특성이 2개일 때에는 평면을 학습하지만 3개가 되면 3차원을 학습한다.
특성이 2개인 경우에는
이렇게 나오고 3개인 경우에는
이런식으로 나오게 된다.
그리고 여기서 높이, 길이를 제외하고 각 특성을 서로 곱하거나 제곱해서 나오는 데이터도 사용하는데 이런 작업을 특성 공학이라고 한다.
import pandas as pd
perch_full = pd.read_csv('https://bit.ly/perch_csv_data')
perch_full.head()
length | height | width | |
---|---|---|---|
0 | 8.4 | 2.11 | 1.41 |
1 | 13.7 | 3.53 | 2.00 |
2 | 15.0 | 3.82 | 2.43 |
3 | 16.2 | 4.59 | 2.63 |
4 | 17.4 | 4.59 | 2.94 |
그리고 train_test_split으로 데이터를 분리한다.
from sklearn.model_selection import train_test_split
import numpy as np
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])
X_train, y_train, X_test, y_test = train_test_split(perch_full, perch_weight, random_state=42)
사이킷런은 모든 모델 클래스에 fit, score, predict 메서드가 있고 이런 클래스를 변환기라고 한다.
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures()
poly.fit([[2,3]])
print(poly.transform([[2,3]]))
특성 2, 3으로 이루어진 샘플을 적용했다.
결과로는 [[1. 2. 3. 4. 6. 9.]]
이 나왔다.
fit과 transform을 동시에 하는 fit_transform()
도 있다.
2, 3
2 ** 2 = 4
3 ** 2 = 9
2 x 3 = 6
이렇게 나오는데 1이 추가되는 이유는 선형 방정식의 절편을 항상 1인 특성과 곱해지는 계수이기 때문이다.
그래서 PolynomialFeatures
의 매개변수로 include_bias=False
를 넣으면 1이 제외된다.
하지만 굳이 이것을 하지 않도라도 모델이 자동으로 제거하기 때문에 그대로 사용해도 된다.
poly.fit(X_train)
X_train_poly = poly.transform(X_train)
X_train_poly.shape
# (42, 10)
X_train의 특성은 length
, weight
, height
3개가 있다.
length
, weight
, height
, length**2
, weight**2
, height**2
, weight x height
, weight x height
, length x height
, length x weight x height
이렇게 10개가 있다.
그리고 이런 결과는 pol.get_feature_names_out()
을 통해서 똑같이 알 수 있다.
특성을 추가한 X_train_poly
로 훈련했다.
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(X_train_poly, X_test)
print(lr.score(X_train_poly, X_test))
# 0.9903183436982125
print(lr.score(y_train_poly, y_test))
# 0.971455991159412
그리고 이런 특성의 개수는 degree
라는 매개변수를 이용하여 늘릴 수 있다.
그렇게 하여 학습하면 거의 1에 가까운 점수가 나오지만 점수를 보면 - 점수가 나온다.
이는 훈련 데이터에 너무 과대적합이 되었기 때문인데, 데이터 개수에 비해 특성이 더 많으면 이런 현상이 일어난다.
과대 적합을 해결하기 위한 여러 방법 중 하나로 규제(regularization)가 있다.
규제는 과도하게 학습하지 못하도록 막는 것이다.
예를 들면
이런식으로 모든 데이터를 학습하는게 아니라 필요 없는 데이터는 학습하지 않게 규제하여 보편적인 패턴을 학습하게 한다.
그리고 이렇게 선형 회귀 모델에 규제를 추가한 모델을 릿지(ridge)와 라쏘(lasso)라고 부린다.
릿지는 계수를 제곱한 값을 기준으로 규제를 적용하고,
라쏘는 계수의 절대값을 기준으로 규제를 적용한다.
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
X_train_scaled = ss.fit_transform(X_train_poly)
y_train_scaled = ss.fit_transform(y_train_poly)
from sklearn.linear_model import Ridge
ridge = Ridge()
ridge.fit(X_train_scaled, X_test)
print(ridge.score(X_train_scaled, X_test))
# 0.9896101671037343
print(ridge.score(y_train_scaled, y_test))
# 0.9790693977615387
테스트 점수가 정상적으로 돌아왔다.
특성을 과도하게 만들었음에도 규제를 통해 과대적합되지 않았다.
alpha
매개변수를 통해 규제 강도를 정할 수 있다.
그리고 적절한 alpha 값을 찾는 방법은 그래프를 그려 alpha 값이 바뀔때 마다 score 점수를 계산한다.
import matplotlib.pyplot as plt
train_scores = []
test_scores = []
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
ridge = Ridge(alpha=alpha)
ridge.fit(X_train_scaled, X_test)
train_scores.append(ridge.score(X_train_scaled, X_test))
test_scores.append(ridge.score(y_train_scaled, y_test))
plt.plot(alpha_list, train_scores, label='train')
plt.plot(alpha_list, test_scores, label='test')
plt.xscale('log')
plt.xlabel('alpha')
plt.ylabel('R^2')
plt.legend()
plt.show()
이 그래프를 통해 최적의 alpha값이 0.1이란 것을 알게 되었다.
from sklearn.linear_model import Lasso
lasso = Lasso()
lasso.fit(X_train_scaled, X_test)
print(lasso.score(X_train_scaled, X_test))
# 0.989789897208096
print(lasso.score(y_train_scaled, y_test))
# 0.9800593698421883
train_scores = []
test_scores = []
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
lasso = Lasso(alpha=alpha, max_iter=10000)
lasso.fit(X_train_scaled, X_test)
train_scores.append(lasso.score(X_train_scaled, X_test))
test_scores.append(lasso.score(y_train_scaled, y_test))
train_scores = []
test_scores = []
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
lasso = Lasso(alpha=alpha, max_iter=10000)
lasso.fit(X_train_scaled, X_test)
train_scores.append(lasso.score(X_train_scaled, X_test))
test_scores.append(lasso.score(y_train_scaled, y_test))
plt.plot(alpha_list, train_scores, label='train')
plt.plot(alpha_list, test_scores, label='test')
plt.xscale('log')
plt.xlabel('alpha')
plt.ylabel('R^2')
plt.legend()
plt.show()
라쏘에서 최적의 alpha값은 10이다.