728x90

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가지는 사용되지 않았다는 뜻이다.이 값을 이용하여 필요하지 않은 특성을 골라낼 수 있다.

728x90

+ Recent posts