keyword : 다중회귀, 특성공학, 릿지, 라쏘, 하이퍼파라미터
multiple regression, feature engineering, Ridge, Lasso, hyperparameter
농어의 무게를 예측하는데 길이 정보만 사용되었다.
높이, 두께 등 다양한 값을 추가하여 예측 성공율을 높여 보자.
PolynomialFeatures Class를 사용할 것이라고 하는데....
다중회귀(multiple regression) : 여러개의 특성을 사용한 선형 회귀
특성공학(feature engineering) : feature engineering란 용어가 이해하기 좀 더 쉽다. 기존의 특성을 이용해 새로운 특성을 만들어내는 작업
이번 예제에서는 '농어 길이 * 농어 높이'를 새로운 특성으로 정의했다.
Pandas : data 분석 library(dataframe 사용)
import pandas as pd
df = pd.read_csv('https://bit.ly/perch_csv_data')
perch_full = df.to_numpy()
print(perch_full)
[[ 8.4 2.11 1.41]
[13.7 3.53 2. ]
[15. 3.82 2.43]
[16.2 4.59 2.63]
[17.4 4.59 2.94]
[18. 5.22 3.32]
[18.7 5.2 3.12]
[19. 5.64 3.05]
....
https://bit.ly/perch_csv_data => https://raw.githubusercontent.com/rickiepark/hg-mldl/master/perch_full.csv
length, height, width
8.4 , 2.11, 1.41
13.7, 3.53, 2.
15. , 3.82, 2.43
16.2, 4.59, 2.63
17.4, 4.59, 2.94
....
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]
)
from sklearn.model_selection import train_test_split
#train data와 test data 생성
train_input, test_input, train_target, test_target = train_test_split(perch_full, perch_weight, random_state=42)
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures()
poly.fit([[2, 3]])
print(poly.transform([[2, 3]]))
[[1. 2. 3. 4. 6. 9.]]
주인공이 나왔다.
fit()은 추가적인 특성을 찾아내고, transform은 값을 넣는다.
2,3을 가지고 특성을 찾았기 때문에 2,3 그리고 2^2, 3^2가 추가되고, 2+3, 2*3도 추가되었다.
그런데 1은? 절편값이라고 하는데 선형모델에서는 자동으로 추가되기 때문에 필요하지 않다고 한다.
이 값을 제거하기 위해 include_bias=False를 준다.
사이킷런에서는 자동으로 False로 해준다고 한다.
poly = PolynomialFeatures(include_bias=False)
poly.fit([[2, 3]])
print(poly.transform([[2, 3]]))
[[2. 3. 4. 6. 9.]]
poly = PolynomialFeatures(include_bias=False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
print(train_poly.shape)
(42, 9)
poly.get_feature_names_out()
array(['x0', 'x1', 'x2', 'x0^2', 'x0 x1', 'x0 x2', 'x1^2', 'x1 x2', 'x2^2'], dtype=object)
get_feature_names_out() : feature가 어떻게 구성되었는지 보여준다.
test_poly = poly.transform(test_input)
다중회귀 모델 훈련하기
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))
0.9903183436982124
훈련점수
print(lr.score(test_poly, test_target))
0.9714559911594132
테스트점수
제곱까지의 변수만 사용하였는데 3승,4승의 항을 넣으려면 degree를 조정하면 된다.(max=5)
poly = PolynomialFeatures(degree=5, include_bias=False)
poly.fit(train_input)
train_poly = poly.transform(train_input)
test_poly = poly.transform(test_input)
print(train_poly.shape)
print(poly.get_feature_names_out())
(42, 55)
['x0' 'x1' 'x2' 'x0^2' 'x0 x1' 'x0 x2' 'x1^2' 'x1 x2' 'x2^2' 'x0^3'
'x0^2 x1' 'x0^2 x2' 'x0 x1^2' 'x0 x1 x2' 'x0 x2^2' 'x1^3' 'x1^2 x2'
'x1 x2^2' 'x2^3' 'x0^4' 'x0^3 x1' 'x0^3 x2' 'x0^2 x1^2' 'x0^2 x1 x2'
'x0^2 x2^2' 'x0 x1^3' 'x0 x1^2 x2' 'x0 x1 x2^2' 'x0 x2^3' 'x1^4'
'x1^3 x2' 'x1^2 x2^2' 'x1 x2^3' 'x2^4' 'x0^5' 'x0^4 x1' 'x0^4 x2'
'x0^3 x1^2' 'x0^3 x1 x2' 'x0^3 x2^2' 'x0^2 x1^3' 'x0^2 x1^2 x2'
'x0^2 x1 x2^2' 'x0^2 x2^3' 'x0 x1^4' 'x0 x1^3 x2' 'x0 x1^2 x2^2'
'x0 x1 x2^3' 'x0 x2^4' 'x1^5' 'x1^4 x2' 'x1^3 x2^2' 'x1^2 x2^3' 'x1 x2^4'
'x2^5']
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))
print(lr.score(test_poly, test_target))
0.9999999999991096
-144.40579242335605
특성의 개수가 많아 훈련 세트에서는 거의 완벽하게 학습이 되지만 과대적합으로 인해 test set에서는 형편없는 점수가 나온다.
규제 : 과대적합을 줄이는 방법
선형회귀 모델의 경우 계수(or 기울기)를 줄여 일반적인 모델로 만들 수 있다.
정규화
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_poly)
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)
train set와 test set는 항상 함께!
Ridge : 계수를 제곱한 값을 기준으로 규제를 적용, alpha값이 클수록 규제가 심해진다.(default=1) solver를 지정할 수 있다.(ㅊ매개변수에 최적의 모델을 찾기 위한 방법 지정 default : solver=auto 추천 : solver=sag, solver=saga (saga는 sag의 개선버전으로 사이킷런 0.19 이후 적용)Lasso : 절댓값을 기준으로 규제를 적용
Ridge
from sklearn.linear_model import Ridge
ridge = Ridge()
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target))
print(ridge.score(test_scaled, test_target))
0.9896101671037343
0.9790693977615397
import matplotlib.pyplot as plt
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()
alpha값을 변경해가며 확인하여 train 점수와 test 점수가 가장 비슷한 alpha가 최적의 값이 된다.
그래프의 왼쪽은 훈련세트에서 점수가 높고 테스트세트에서 점수가 낮은 과대적합, 오른쪽은 둘 다 점수가 낮아지는 과소적합의 모습을 보인다.
여기에서는 0.1이 최적의 값이 되었다.
ridge = Ridge(alpha=0.1)
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target))
print(ridge.score(test_scaled, test_target))
0.9903815817570366
0.9827976465386927
Lasso
Rigde와 동일하게 사용하고 이름을 Lasso로 바꾼다.
from sklearn.linear_model import Lasso
lasso = Lasso()
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target))
print(lasso.score(test_scaled, test_target))
0.989789897208096
0.9800593698421883
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()
이 결과에서 최적값은 alpha=1 값이다. 즉 10^1 = 10 이다.
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.9888067471131867
0.9824470598706695
print(np.sum(lasso.coef_ == 0))
40
Lasso모델은 계속의 값을 0으로 설정할 수도 있다. 55가지 특성 중 40가지는 사용되지 않았다는 뜻이다.이 값을 이용하여 필요하지 않은 특성을 골라낼 수 있다.
'Programming > Machine Learning' 카테고리의 다른 글
[혼공머신] 05-2 교차 검증과 그리드 서치 (0) | 2022.02.12 |
---|---|
[혼공머신] 05-1 결정트리 (0) | 2022.02.06 |
[혼공머신] 04-2 확률적 경사 하강법 (0) | 2022.02.05 |
[혼공머신] 용어 03장 (0) | 2022.02.03 |
[혼공머신] 04-1 로지스틱 회귀 (0) | 2022.01.23 |
[혼공머신] 03-2 선형 회귀 (0) | 2022.01.16 |
[혼공머신] 용어 02장 (0) | 2022.01.16 |
[혼공머신] 03-1 k-최근접 이웃회귀 (0) | 2022.01.09 |
[혼공머신] 02-2 데이터 전처리(data preprocessing) (0) | 2022.01.08 |
[혼공머신] 용어 01장 (0) | 2022.01.05 |