본문 바로가기
Machine Learning

[혼자 공부하는 머신러닝 + 딥러닝] 특성 공학과 규제

by 가론노미 2023. 4. 21.

[혼자 공부하는 머신러닝+딥러닝] 책의 내용을 정리한 글 입니다.

개념

다중 회귀

: 다중 회귀(multiple regression)란 여러 개의 특성을 사용하는 회귀 모델이다.

→ 특성이 많으면 선형 모델은 강력한 성능을 발휘한다.

특성 공학

: 주어진 특성을 조합하여 새로운 특성을 만드는 일련의 작업 과정

ex) 농어 길이 x 농어 높이

규제

: 머신러닝 모델이 훈련 세트를 너무 과도하게 학습하지 못하도록 훼방하는 것을 말한다. (= 훈련 세트에 과대적합되지 않도록 한다.)

선형 회귀 모델에서 규제는 어떻게 이루어질까?

선형 회귀 모델에 규제 추가한다는 것은 특성에 곱해지는 계수(또는 기울기)의 크기를 작게 만드는 일이다.

  • 릿지
    • 규제가 추가된 선형 회귀 모델 중 하나이며, 비교적 효과가 좋아 널리 사용하는 규제 방법이다.
    • 계수, 즉 가중치를 제곱한 값을 기준으로 규제를 적용한다.
  • 라쏘
    • 또 다른 규제가 있는 선형 회구 모델 중 하나이다.
    • 계수의 절대값을 기준으로 규제를 적용한다.
    • 릿지와 달리 계수 값을 아예 0으로 만들 수 있다. (이런 특징으로 유용한 특성을 골라내는 용도로도 사용할 수 있다)

하이퍼파라미터

: 머신러닝 알고리즘이 학습하지 않는 파라미터

  • 사람이 사전에 지정해야 한다.
  • 대표적으로 릿지와 라쏘의 규제 강도 alpha 파라미터를 예로 들 수 있다.

코드 작성

다중 회귀 모델과 릿지, 라쏘 모델을 알아보고 과대적합을 제어한 최적의 모델을 훈련시켜보자.

판다스와 넘파이를 사용하여 농어의 특성 데이터(길이, 높이, 두께) 및 타깃 데이터(무게) 준비

import pandas as pd

df = pd.read_csv('https://bit.ly/perch_csv_data')
perch_full = df.to_numpy()

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)

사이킷런의 변환기인 PolynomialFeatures 클래스를 사용하여 새로운 특성 생성

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)

# 새로운 특성이 각각 어떤 입력의 조합으로 만들어졌는지 확인
poly.get_feature_names_out()
# => array(['x0', 'x1', 'x2', 'x0^2', 'x0 x1', 'x0 x2', 'x1^2', 'x1 x2', 'x2^2'], dtype=object)

여러개의 특성을 사용한 다중 회귀 모델 훈련

from sklearn.linear_model import LinearRegression

lr = LinearRegression()
lr.fit(train_poly, train_target)
print(lr.score(train_poly, train_target))
# => 0.9903183436982125

print(lr.score(test_poly, test_target))
# => 0.9714559911594111

특성을 더 많이 추가한 다중 회귀 모델 점수 확인

# degree를 통해 고차항의 최대 차수를 지정 (5제곱까지 생성)
poly = PolynomialFeatures(degree=5, include_bias=False)

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))
# => 0.9999999999996433

print(lr.score(test_poly, test_target))
# => -144.40579436844948

많은 특성들로 인해 훈련 세트에 대해 거의 완벽하게 학습하여 과대적합 되었다

과대적합을 줄이기 위해 규제를 추가한 모델을 훈련해보고, 규제 양을 조절하기 위한 최적의 alpha 값을 찾아보자


규제 추가하기 전에 공정하게 계수가 제어될 수 있도록 특성의 스케일 정규화 진행

from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
ss.fit(train_poly)

train_scaled = ss.transform(train_poly)
test_scaled = ss.transform(test_poly)

릿지 모델 훈련

from sklearn.linear_model import Ridge
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 값에 대한 테스트 세트(주황)와 훈련 세트(파랑) score

가장 최적의 파라미터 값인 0.1 ($10^-1$=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.9903815817570367
# => 0.9827976465386928

라쏘 모델 훈련

from sklearn.linear_model import Lasso

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 값에 대한 테스트 세트(주황)와 훈련 세트(파랑) score

가장 최적의 파라미터 값인 10 ($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

라쏘 모델에서 계수 값을 0으로 만든 특성 개수 확인

print(np.sum(lasso.coef_ == 0))
# => 40 (55개의 특성 중 15개의 특성만 사용했다는 것을 알 수 있다)

이 장에서 사용된 핵심 패키지와 함수

pandas

  • read_csv()
    • CSV 파일을 로컬 컴퓨터나 인터넷에서 읽어 판다스 데이터프레임으로 변환하는 함수
    • sep - CSV 파일의 구분자 지정 (기본값 - 콤마)
    • header - 데이터프레임의 열 이름으로 사용할 CSV 파일의 행 번호 지정
    • skiprows - 파일에서 읽기 전에 건너뛸 행의 개수를 지정
    • nrows - 파일에서 읽을 행의 개수를 지정

scikit-learn

  • PolynomialFeatures
    • 주어진 특성을 조합하여 새로운 특성을 만듦
    • degree - 최고 차수를 지정 (기본값 - 2)
    • interaction_only - True이면 거듭제곱 항은 제외되고 특성 간의 곱셈 항만 추가 (기본값 - False)
    • include_bias - False이면 절편을 위한 특성을 추가하지 않음 (기본값 - True)
  • Ridge
    • 규제가 있는 회귀 알고리즘인 릿지 회귀 모델을 훈련
    • alpha - 규제의 강도를 조절, 값이 클 수록 규제가 세짐
    • solver - 최적의 모델을 찾기 위한 방법을 지정 (기본값 - auto)
  • Lasso
    • 규제가 있는 회귀 알고리즘인 라쏘 회귀 모델을 훈련 (좌표축을 따라 최적화를 수행해가는 좌표 하강법을 사용)
    • alpha - 규제의 강도를 조절, 값이 클 수록 규제가 세짐
    • max_iter - 알고리즘의 수행 반복 횟수를 지정 (기본값 - 1000)