[혼공머신] 다중회귀와 특성공학, 릿지·랏쏘 회귀

강민우·2022년 1월 13일
0
post-thumbnail

[혼자 공부하는 머신러닝+딥러닝] 책에 기반한 정리글입니다.
전체 소스코드는 아래 Github 링크에서 확인할 수 있습니다.

Github 링크

0. 개요

다중 회귀

  • 다중 회귀란 여러 개의 특성을 사용한 선형 회귀
  • 1개의 특성은 직선을, 2개의 특성은 평면을 학습
  • 특성이 많다면 매우 복잡한 모델 표현 가능

특성 공학
각각의 특성을 제곱하고, 특성끼리 곱하는 등 기존의 특성으로 새로운 특성을 뽑아내는 작업

이 포스팅에서는 농어의 무게를 예측하는 과정에서 길이 뿐만이 아닌 높이, 두께를 추가로 사용하며, 특성 공학으로 추가적인 특성을 만든다.

1. 훈련 데이터 준비하기

pandas를 사용하여 .csv파일을 numpy 배열로 만든다.

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') #온라인에서 csv파일로 dataframe생성

perch_full = df.to_numpy() # numpy배열로 변환
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])

#훈련 모델과 테스트 모델 나누기
#동일한 결과를 내기위해 random_state 사용
train_input, test_input, train_target, test_target = train_test_split(perch_full, perch_weight, random_state=42)

2. 훈련 데이터의 특성 변환과 모델 훈련

2-1. PolynomialFeatures 클래스로 특성 변환

sklearn.preprocessingPolynomialFeatures를 import한다.
변환기 객체 생성 후 객체 훈련, 특성 변환을 해준다.

#사이킷런 변환기
# 변환기 객체 만들고 모델 훈련, 변환
from sklearn.preprocessing import PolynomialFeatures

poly = PolynomialFeatures(include_bias = False)
#사이킷런의 선형 모델은 자동으로 절편을 추가하기 때문에 include_bias를 False로.
#굳이 지정하지 않아도 사이킷런은 자동으로 특성에 추가된 절편 항 무시함

poly.fit(train_input)
train_poly = poly.transform(train_input)
test_poly = poly.transform(test_input) #훈련 세트를 기준으로 테스트세트도 변환

특성 배열의 형태와 만들어진 특성이 어떤 조합으로 이루어졌는지 확인한다.

print(train_poly.shape) # 9개의 특성값이 생김
print(poly.get_feature_names()) # 9개의 특성이 어떻게 만들어졌는지 보여줌

출력
(42, 9)
['x0', 'x1', 'x2', 'x0^2', 'x0 x1', 'x0 x2', 'x1^2', 'x1 x2', 'x2^2']

9개의 특성값이 생김을 확인하고, 각각의 특성을 제곱하거나 서로 곱해 만들어짐을 확인할 수 있다.

2-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.9714559911594132

과대, 과소적합 문제가 일어나지 않았다.

다중 회귀 모델을 훈련하는 것은 선형 회귀 모델을 훈련하는 것과 같다.

2-3. 5제곱까지 특성을 만들어 훈련해보기

PolynomialFeatures 클래스의 degree 매개변수로 필요한 고차항의 최대 차수를 지정할 수 있다.

# 5제곱까지 특성을 만들어 결정계수 확인
poly = PolynomialFeatures(degree = 5, include_bias=False) #degree가 차수를 결정
poly.fit(train_input)

train_poly = poly.transform(train_input)
test_poly = poly.transform(test_input)

lr.fit(train_poly, train_target)

print(lr.score(train_poly, train_target)) #훈련세트
print(lr.score(test_poly, test_target)) #테스트세트

출력
0.9999999999991096
-144.40579242335605

훈련세트의 결정계수는 매우 높게 나왔음에도 불구하고 테스트세트의 결정계수는 음수가 나왔다.

훈련세트에 너무 과대적합되어 테스트세트가 나쁜 점수가 나온다는 것을 알 수 있다.

3. 과대적합을 막는 릿지·랏쏘 회귀

모델이 훈련 세트에 과대적합되지 않도록 규제(regualrization)이 필요하다. 선형 회귀 모델에서는 특성에 곱해지는 계수의 크기를 작게 만드는 것이다.

선형 회귀 모델에 규제를 적용하려면, 특성의 정규화가 필요하다.

3-1. 특성을 표준점수로 변환하기

sklearn.preprocessingStandardScaler 클래스를 import한다.
객체 훈련 후 훈련세트와 테스트세트를 정규화시킨다.

from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
ss.fit(train_poly)

# 표준점수로 변환
train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)

3-2. 정규화된 특성으로 릿지 모델 훈련

릿지는 계수를 제곱한 값을 기준으로 규제를 적용한다.

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

과대적합되지 않음을 알 수 있다.

한편, 규제의 양을 임의로 조절할 수 있다.
모델 객체를 만들 때 alpha 매개변수로 규제의 강도를 조절한다.

  • alpha값이 크면 규제 강도가 세져 계수 값을 더 줄이고 조금 더 과소적합하도록 유도한다.
  • alpha값이 작으면 규제 강도가 약해져 계수를 줄이는 역할이 줄어들어 과대적합될 가능성이 커진다.

적절한 alpha 값을 찾는 방법 중 하나는 alpha값에 따른 R^2 그래프를 그려보는 것이다.
alpha값을 0.001부터 10배씩 늘리면서 R^2값의 변화를 그린다.

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) # alpha값 매개변수
  ridge.fit(train_scaled, train_target)

  # 결정계수값 리스트에 append
  train_score.append(ridge.score(train_scaled, train_target))
  test_score.append(ridge.score(test_scaled, test_target))

# alpha값이 왼쪽에 너무 몰리기 때문에 log10으로 표현
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 값으로는 0.1이라는 것을 알 수 있다.

3-3. 정규화된 특성으로 라쏘 모델 훈련

라쏘는 계수의 절대값을 기준으로 규제를 적용한다.
릿지와 라쏘 모두 계수의 크기를 줄이지만, 라쏘는 계수를 0으로 만들 수도 있다.

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

역시 과대적합을 잘 억제하였다.

마찬가지로 alpha값으로 규제 강도를 조절할 수 있다.

train_score = []
test_score = []

alpha_list = [0.001, 0.01, 0.1, 1, 10, 100]

for _alpha in alpha_list :
  lasso = Lasso(alpha=_alpha) # alpha값 매개변수
  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값은 10임을 알 수 있다.

한편, 라쏘 모델은 계수 값을 0으로 만들 수 있다는 특성 때문에 유용한 특성을 골라 내는 용도로도 사용할 수 있다.

# 라쏘 모델의 계수는 lasso.coef_ 에 저장되어 있음
lasso = Lasso(alpha = 10)
lasso.fit(train_scaled, train_target)
print(np.sum(lasso.coef_ == 0))

라쏘 모델의 40개의 특성의 계수는 0임을 알 수 있다.

profile
어제보다 성장한 오늘

0개의 댓글