[chap 3-3] 특성 공확과 규제
❗ 문제점 ❗
앞 장에서 어느 정도 훈련 세트와 테스트 세트의 점수가 맞추어졌지만 그래도 여전히 테스트 세트의 점수가 높다. 이를 해결하기 위해서는 다항 회귀로 하기 위해서는 많은 수동 작업이 필요해서 귀찮다.
💡 해결책 💡
다중 회귀. 선형 회귀인 경우 하나의 특성만을 가지고 농어의 무게를 예측했다면, 다중 회귀는 여러 개의 특성을 사용한 선형 회귀를 다중 회귀 라고 한다.
- 특성 공학 : 기존의 특성을 사용하여서 새로운 특성을 뽑아내는 것
1️⃣ 데이터 준비
📦 판다스
넘파이와 비슷하지만 이번 장은 3개의 특성을 사용할 것이기 때문에 하나하나 복사해서 넘파이 배열로 만들기 귀찮다. 다차원 배열을 다룰 수 있고, 더 많은 기능을 제공하는 판다스를 통해서 데이터를 준비한다.
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
df = pd.read_csv('https://bit.ly/perch_csv_data')
perch_full = df.to_numpy()
print(perch_full) # 길이, 높이, 두께 3가지 특성을 가진 2차원 배열을 만든다.
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])
train_input, test_input, train_target, test_target = train_test_split(perch_full, perch_weight, random_state = 42)
print(train_input.shape)
print(test_input.shape)
>>> 출력값
(42, 3)
(14, 3)
변환기 클래스 사용하여 특성 늘리기
- 사이킷런
- 모델 클래스
- KNeighborsClassifier
- KNeighborsRegressor
- LinearRegression
- 변환기 클래스
- PolynomialFeatures
- StandardScaler
- 모델 클래스
변환기 클래스의 경우 fit(), transform() 메소드가 있는데, fit을 통해서 새롭게 만들 특성의 조합을 찾고, transform을 통해서 실제로 데이터를 만드는 것이다.
예제
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(include_bias = False)
poly.fit([[2, 3]])
print(poly.transform([[2, 3]]))
>>> 출력값
[[2. 3. 4. 6. 9.]]
💡 활용
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(include_bias = False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
test_poly = poly.transform(test_input)
print(train_poly.shape)
print(test_poly.shape)
>>> 출력값
(42, 9)
(14, 9)
특성이 3개에서 9개로 늘어난 것을 확인할 수 있다.
2️⃣ 다중 회귀 모델 훈련하기
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))
print(lr.score(test_poly, test_target))
>>> 출력값
0.9903183436982124
0.9714559911594134
❓ 현재는 제곱까지의 특성을 가지고 구했는데 만약에 5제곱까지 특성을 만들면 어떻게 될까?
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
poly = PolynomialFeatures(degree = 5, include_bias = False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
test_poly = poly.transform(test_input)
lr = LinearRegression()
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))
print(lr.score(test_poly, test_target))
>>> 출력값
0.9999999999991097
-144.40579242684848
??? 특성의 개수를 늘리면 선형 모델은 아주 강력해져서 엄청만 과대적합이 되었다. 과대적합이 되었으니 훈련세트의 복잡도를 낮추면 된다.
3️⃣ 규제를 위한 방법 : 릿지와 라쏘
머신 러닝 모델이 훈련 세트를 너무 과도하게 학습하지 못하도록 훼방하는 것을 말한다. 앞 장에서는 훈련 세트와 테스트 세트의 전반적인 점수가 낮아서 과소적합되었기 때문에 복잡도를 높이기 위해서 다항 회귀를 사용하였다. 하지만 현재는 엄청난 과대적합되었으므로, 과대적합되지 않도록 만들어 주어야 한다. 👉 선형 회귀 모델의 경우 특성에 곱해지는 계수의 크기를 작게하면 된다.
선형 회귀 모델에 규제를 적용할 때, 계수의 값의 크기가 서로 많이 다르면 공정하게 제어되지 않는다. 2장 처럼 정규화 과정이 필요하다. 2장에서는 표준 점수를 사용하여 정규화를 하였지만, 이번에는 StandardScaler 를 사용하여 정규화를 해본다.
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_poly)
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)
- 릿지 && 라쏘 : 선형 회귀 모델에 규제를 추가한 모델, alpha를 통해서 프로그래머가 임의로 규제값을 조정할 수 있다. alpha가 크면 규제 강도가 세지므로 조금 더 과소적합되도록 유도하고 작으면 과대적합될 가능성이 크다. 👉 그럼 가장 적합한 alpha값 어떻게 찾아? 그래프를 그려보자!
4️⃣ 가장 적합한 alpha 찾기
릿지
from sklearn.linear_model import Ridge
import matplotlib.pyplot as plt
ridge = Ridge()
ridge.fit(train_scaled, train_target)
train_score = []
test_score = []
alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]
for alpha in alpha_list:
ridge = Ridge(alpha=alpha)
ridge.fit(train_scaled, train_target)
train_score.append(ridge.score(train_scaled, train_target))
test_score.append(ridge.score(test_scaled, test_target))
plt.plot(np.log10(alpha_list), train_score)
plt.plot(np.log10(alpha_list), test_score)
plt.xlabel('alpha')
plt.ylabel('R^2')
plt.show()
이 그래프에서 훈련 세트와 테스트 세트의 점수 차가 가장 적은 0.1이 alpha로 가장 적합함을 알 수 있다.
라쏘
from sklearn.linear_model import Lasso
import matplotlib.pyplot as plt
lasso = Lasso()
lasso.fit(train_scaled, train_target)
train_score = []
test_score = []
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(train_scaled, train_target)
train_score.append(lasso.score(train_scaled, train_target))
test_score.append(lasso.score(test_scaled, test_target))
plt.plot(np.log10(alpha_list), train_score)
plt.plot(np.log10(alpha_list), test_score)
plt.xlabel('alpha')
plt.ylabel('R^2')
plt.show()
위 그래프에서는 10이 alpha값으로 가장 적절한 것을 알 수 있다.
🌗 최종
ridge = Ridge(alph = 0.1)
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target))
print(ridge.score(test_scaled, test_target))
>>> 출력값
0.9896101671037343
0.9790693977615397
lasso = Lasso(alpha = 10)
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target))
print(lasso.score(test_scaled, test_target))
>>> 출력값
0.989789897208096
0.9800593698421883
댓글남기기