모델에는 두 종류의 설정값이 있습니다. 하나는 가중치처럼 데이터로부터 학습되는 매개변수이고, 다른 하나는 학습이 시작되기 전에 사람이 정해 주어야 하는 값입니다. 후자를 하이퍼파라미터(hyperparameter) 라 합니다. kNN의 이웃 수, 릿지의 alpha, SVM의 C 같은 값들이 여기에 해당합니다.
일반화 성능은 하이퍼파라미터 설정에 크게 좌우됩니다. 그래서 좋은 설정을 찾는 모델 튜닝은 거의 모든 모델과 데이터셋에서 반드시 거쳐야 하는 작업입니다. 이 절에서는 여러 설정을 체계적으로 시험해 최적값을 찾는 방법을 살펴봅니다.
1파이프라인¶
대부분의 모델은 단위 변환 같은 전처리를 먼저 거칩니다. 전처리와 모델을 따로 두면, 설정을 바꿔 가며 반복 평가할 때 매번 두 단계를 손으로 맞춰 주어야 합니다. 파이프라인(Pipeline) 은 이런 단계들을 하나의 흐름으로 묶어 줍니다.
캘리포니아 주택 데이터에 단위 변환과 kNN 회귀를 묶어 보겠습니다.
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import RobustScaler
from sklearn.neighbors import KNeighborsRegressor
import pandas as pd
housing = fetch_california_housing()
훈련데이터, 시험데이터, 훈련정답, 시험정답 = train_test_split(
housing.data, housing.target, random_state=4)
model = Pipeline([
('scaler', RobustScaler()),
('knn', KNeighborsRegressor()),
])
model파이프라인의 핵심은, 묶인 결과 역시 하나의 추정기처럼 동작한다는 점입니다. 단일 모델과 똑같이 fit, predict, score 메서드를 제공하므로, 내부가 단일 회귀기든 전처리와 회귀기를 묶은 파이프라인이든 같은 방식으로 다룰 수 있습니다. 또한 단위 변환의 기준은 훈련 데이터에서만 학습되어 시험 데이터에 일관되게 적용되므로, 평가 과정에서 정보가 새는 것을 막아 줍니다.
2격자 탐색¶
이제 하이퍼파라미터를 바꿔 가며 성능을 봅니다. kNN에는 거리 척도 p(1이면 맨해튼, 2면 유클리드)와 이웃 수라는 두 설정이 있습니다. 두 설정의 가능한 조합을 표처럼 펼쳐 각 칸의 성능을 채워 넣어 보겠습니다. 한 설정을 가로축, 다른 설정을 세로축에 두면 결과가 격자(grid) 모양이 됩니다 — 격자 탐색이라는 이름은 여기서 왔습니다.
파이프라인의 특정 단계 매개변수는 단계이름__매개변수 형식으로 설정합니다(knn__n_neighbors).
점수표 = {}
for p in [1, 2]:
for 이웃수 in range(1, 11, 2):
model.set_params(knn__p=p, knn__n_neighbors=이웃수)
model.fit(훈련데이터, 훈련정답)
점수표[(p, 이웃수)] = model.score(시험데이터, 시험정답)
pd.Series(점수표).round(3).rename_axis(['p', '이웃수']).to_frame('R^2')표를 보면 거리 척도와 이웃 수에 따라 성능()이 달라집니다. 이렇게 조합을 손으로 펼쳐 보면 어떤 설정이 좋은지 알 수 있지만, 조합이 많아지면 직접 반복문을 짜는 것은 번거롭습니다.
3GridSearchCV¶
격자 탐색은 매우 흔한 작업이라 사이킷런이 GridSearchCV 로 자동화해 둡니다. 탐색할 매개변수 후보를 사전으로 주면, 가능한 조합을 차례로 시험해 가장 좋은 설정을 찾습니다. 이름 끝의 CV 는 각 조합을 교차 검증(cross validation) 으로 평가한다는 뜻으로, 한 번의 분할에 의존하지 않아 더 안정적입니다.
from sklearn.model_selection import GridSearchCV
탐색범위 = {
'knn__n_neighbors': range(1, 11, 2),
'knn__p': [1, 2],
}
튜닝기 = GridSearchCV(model, param_grid=탐색범위)
튜닝기.fit(훈련데이터, 훈련정답)
print('최적 설정:', 튜닝기.best_params_)
print(f'시험 R^2: {튜닝기.score(시험데이터, 시험정답):.3f}')최적 설정: {'knn__n_neighbors': 9, 'knn__p': 1}
시험 R^2: 0.704
fit 한 번으로 모든 조합을 교차 검증하고, 가장 좋은 설정을 best_params_ 에 담습니다. 학습이 끝난 튜닝기 는 자동으로 최적 설정의 모델로 동작하므로, 그대로 score 나 predict 에 쓸 수 있습니다.
전체 탐색 과정은 cv_results_ 에 기록됩니다. 표로 펼쳐 각 조합의 평균 점수와 순위를 확인해 보겠습니다.
결과표 = pd.DataFrame(튜닝기.cv_results_)
결과표[['param_knn__n_neighbors', 'param_knn__p', 'mean_test_score', 'rank_test_score']] \
.round(3).sort_values('rank_test_score').head()정리하면, 모델 튜닝은 학습되지 않는 하이퍼파라미터의 좋은 값을 찾는 작업입니다. 전처리와 모델을 파이프라인으로 묶어 하나의 추정기로 다루고, 격자 탐색으로 설정 조합을 체계적으로 시험하며, GridSearchCV 로 이 과정을 교차 검증과 함께 자동화합니다.