머신러닝(ML) & 딥러닝(DL)/혼자공부하는 머신러닝 딥러닝

Chapter 03-3. 특성 공학과 규제

Kim MyeongOk 2022. 12. 5. 17:29
특성 공학: 새로운 특성을 추가하거나 특성을 변경하거나, 조합하는 것을 뜻함.
 

pandas 라이브러리

  • 과학라이브러리- numpy, scipy, pandas
  • pandas는 DataFrame이라는 객체를 사용함.
  • 엑셀과 같이 행렬을 사용하며, 각 셀을 수정 및 변경 가능함
  • DataFrame 객체를 numpy배열로 형변환할 때: DataFrame객체명.to_numpy()
 

 

다중 회귀 (Multiple regression = Multinomial regression)

import pandas as pd
df = pd.read_csv('http://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]
 [19.6   5.14  3.04]
 [20.    5.08  2.77]
 [21.    5.69  3.56]
 [21.    5.92  3.31]
 [21.    5.69  3.67]
 [21.3   6.38  3.53]
 [22.    6.11  3.41]
 [22.    5.64  3.52]
 [22.    6.11  3.52]
 [22.    5.88  3.52]
 [22.    5.52  4.  ]
 [22.5   5.86  3.62]
 [22.5   6.79  3.62]
 [22.7   5.95  3.63]
 [23.    5.22  3.63]
 [23.5   6.28  3.72]
 [24.    7.29  3.72]
 [24.    6.38  3.82]
 [24.6   6.73  4.17]
 [25.    6.44  3.68]
 [25.6   6.56  4.24]
 [26.5   7.17  4.14]
 [27.3   8.32  5.14]
 [27.5   7.17  4.34]
 [27.5   7.05  4.34]
 [27.5   7.28  4.57]
 [28.    7.82  4.2 ]
 [28.7   7.59  4.64]
 [30.    7.62  4.77]
 [32.8  10.03  6.02]
 [34.5  10.26  6.39]
 [35.   11.49  7.8 ]
 [36.5  10.88  6.86]
 [36.   10.61  6.74]
 [37.   10.84  6.26]
 [37.   10.57  6.37]
 [39.   11.14  7.49]
 [39.   11.14  6.  ]
 [39.   12.43  7.35]
 [40.   11.93  7.11]
 [40.   11.73  7.22]
 [40.   12.38  7.46]
 [40.   11.14  6.63]
 [42.   12.8   6.87]
 [43.   11.93  7.28]
 [43.   12.51  7.42]
 [43.5  12.6   8.14]
 [44.   12.49  7.6 ]]
 '''
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_input, test_input, train_target, test_target = train_test_split(
    perch_full, perch_weight, random_state=42)

사이킷런의 변환기

  1. 사이킷런은 특성을 만들거나 전처리하기 위한 다양한 클래스를 제공한다.
  2. 모델 클래스(=추정기): KNeighborsClassifier, KNeighborsRegressor, LinearRegression
    • fit(), score(), predict()
  3. 변환기 클래스: PolynomialFeatures
    • fit(), transform()
from sklearn.preprocessing import PolynomialFeatures
#                                 _____________________
#                                   변환기: Transformer
#                                 ≠추정기: Estimator

#degree = 2
poly = PolynomialFeatures(include_bias=False)
poly.fit([[2, 3]])
# fit()메소드의 역할: 학습하는 것은 아님
#                     특성의 개수, 특성 조합의 방향을 파악하는 역할
# fit_transform()메소드로 특성을 제곱하거나 특성들을 곱해서 새로운 특성데이터 새로운 배열을 만들어준다. 


# 1(bias), 2, 3, 2**2, 2*3, 3**2
# _______
# 절편을 위한 가상의 특성
# 그러나 선형회귀에서 1을 무시함
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()
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.9714559911594134
'''
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)
'''
(42, 55)
'''
lr.fit(train_poly, train_target)
lr.score(train_poly, train_target)
'''
0.9999999999991097
'''
lr.score(test_poly, test_target)
# 위 코드는 과대적합된 예시
'''
-144.40579242684848
'''

규제

  • 각 샘플에 잘맞는 모델이 있는데, 이 과대적합된 모델을 규제(정규화)를 통해서 일반화된 모델로 만드는 것으로 가중치(기울기)를 작게한다.
  • 규제의 역할: 가중치를 작게하는 것
  • ex) 릿지, 라쏘

  • polynomifeatures에서는 훈련데이터을 fit()한것만 사용함

  • 선형회귀는 스케일에 영향을 받지 않음
  • 그러나 규제를 하게되면 상황이 달라짐
  • 가중치가 크면 벌칙을 내림으로 가중치를 낮게함.
  • 특성의 스케일이 비슷해져야 기울기도 비슷해진다.
  • 각 기울기가 비슷해야 각 특성에 주어지는 벌칙이 공평해진다.
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_poly)
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)

릿지 회귀

  • (가중치)^2을 벌칙으로 사용함
  • 가중치는 "모델파라미터"라고 부름
  • 그래서 릿지를 "L2규제"라고도 부름

# alpha

  • 릿지 클래스에 강도가 있음
  • alpha 매개변수의 기본값 = 1 (하이퍼파라미터)
  • alpha 매개변수가 커지면 강도가 커짐
  • alpha 매개변수가 작아지면 강도가 작아짐
  • 어떤 강도가 훈련세트와 테스트세트의 점수를 높게 표현하는지 보려면 적용해보는 수 밖에 없음
  • 좋은 스코어 점수가 나오는 것을 찾는것을 "하이퍼파라미터 탐색"이라고 부름
from sklearn.linear_model import Ridge
ridge = Ridge()
ridge.fit(train_scaled, train_target)
print(ridge.score(train_scaled, train_target))
'''
0.9896101671037343
'''
print(ridge.score(test_scaled, test_target))
'''
0.9790693977615391
'''
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()
# 훈련세트와 테스트세트의 차이가 너무 크다.
# 좋은 모델이 아니다.

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.9903815817570365
0.9827976465386884
'''

라쏘 회귀

  • 라쏘에서는 가중치의 절대값을 벌칙으로하는 "L1규제"
from sklearn.linear_model import Lasso
lasso = Lasso()
lasso.fit(train_scaled, train_target)
print(lasso.score(train_scaled, train_target))
'''
0.989789897208096
'''
print(lasso.score(test_scaled, test_target))
'''
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
'''
  • L1규제보다는 L2규제를 더 선호함
  • L1규제에서는 가중치를 "0(영)"으로 설정가능함

 

  • 특성*가중치
  • 특성*0(영)이 되면 결과가 0(영)이 되므로 가중치를 사용하지 않은 것이 됨
  • 특성을 사용한지 아닌지 알려면 라쏘 객체의 기울기에 값이 들어있으니 0(영)인것만 True값으로 더하면 40개가 나온것을 알 수 있다.

 

  • 과대적합을 규제(억제)하기 위해 L1, 혹은 L2규제를 사용함

 

[질의응답]
  • 알고리즘과 클래스는 별개의 문제이다.
  • 라이브러리마다 주제파라미터 등 좋은 값을 기본값으로 설정되어있음. 그러나 기본값을 바꿔가면서 최적의 모델을 찾는것이 중요하다.

 

 

  • 알고리즘의 구현방법을 알려면 이론을 살펴봐야하고, 사이킷런의 오픈소스를 열어보고 읽어보면서 공식을 봤을때, 소스코드를 보면서 이해하기 좋음
  • 그렇게 보면 알고리즘을 볼때, 좀더 이해하기 편하고 좋을 것임

AI의 기본은 수학?
  • AI가 수학이나 통계의 기반을 두는 경우가 많음
  • 방법론도 수학이나 통계학적이나, 경험론적인것도 포함되어 있다.
  • 미적분이나 통계학을 배우는 것은 알고리즘을 이해하기 위함
  • 알고리즘을 개발하고 연구하는 것이라면 수학, 통계학은 필수적임
  • 알고리즘으로 문제를 풀어가는 입장이라면 수학이나 이론은 내가 더 잘 쓰기 위함임