🔥알림🔥
① 테디노트 유튜브 -
구경하러 가기!
② LangChain 한국어 튜토리얼
바로가기 👀
③ 랭체인 노트 무료 전자책(wikidocs)
바로가기 🙌
④ RAG 비법노트 LangChain 강의오픈
바로가기 🙌
⑤ 서울대 PyTorch 딥러닝 강의
바로가기 🙌
머신러닝 실전 앙상블 (Ensemble)과 Hyperparameter 튜닝
머신러닝 알고리즘의 끝판왕인 앙상블(Ensemble) 알고리즘에 대하여 알아보도록 하겠습니다. 앙상블 알고리즘은 방법론 적인 측면에서 Voting, Bagging, Boosting 알고리즘등으로 나뉠 수 있겠고, 앙상블의 앙상블 알고리즘인 Stacking 그리고 Weighted Blending 등의 기법도 알아보도록 하겠습니다. 앙상블 알고리즘은 단일 알고리즘 대비 성능이 좋기 때문에, 캐글(Kaggle.com)과 같은 데이터 분석 대회에서도 상위권에 항상 꼽히는 알고리즘 들입니다.
데이터의 종류, 형태에 따라 어떤 알고리즘이 우세한지는 직접 적용해보고 성능 평가를 통해 알아볼 수는 있겠지만, 최근에는 LGBM 그리고 XGBoost와 같은 부스팅 계열의 알고리즘이 대회의 상위권을 휩쓸고 있습니다. 부스팅 계열의 앙상블 알고리즘이 정형 데이터에서 강세를 보이고 있습니다.
이 튜토리얼의 후반부에는 RandomSearchCV
와 GridSearchCV
라는 Hyperparameter 튜닝기도 다루고 있습니다. 물론, 시간과 리소스가 많이 투여되는 부부이기 때문에 최근에는 bayesian optimization을 기반으로 찾는 HyperOpt
도 주목 받고 있습니다. 나중에 HyperOpt
에 대한 내용도 다뤄보도록 하겠습니다.
튜토리얼은 보스톤 집 값 데이터를 토대로 집 값 예측을 해보는 튜토리얼이며, sklearn.dataset
에 포함된 load_boston
으로 진행합니다. 따라서, 별도의 파일 데이터는 다운로드 받을 필요 없습니다.
코드
앙상블(Ensemble)
머신러닝 앙상블이란 여러개의 머신러닝 모델을 이용해 최적의 답을 찾아내는 기법이다.
- 여러 모델을 이용하여 데이터를 학습하고, 모든 모델의 예측결과를 평균하여 예측
앙상블 기법의 종류
- 보팅 (Voting): 투표를 통해 결과 도출
- 배깅 (Bagging): 샘플 중복 생성을 통해 결과 도출
- 부스팅 (Boosting): 이전 오차를 보완하면서 가중치 부여
- 스태킹 (Stacking): 여러 모델을 기반으로 예측된 결과를 통해 meta 모델이 다시 한번 예측
참고자료 (블로그)
실습을 위한 데이터셋 로드
# 튜토리얼 진행을 위한 모듈 import
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from IPython.display import Image
np.set_printoptions(suppress=True, precision=3)
SEED = 30
from sklearn.datasets import load_boston
load_boston
데이터셋 로드
data = load_boston()
컬럼 소개
속성 수 : 13
- CRIM: 범죄율
- ZN: 25,000 평방 피트 당 주거용 토지의 비율
- INDUS: 비소매(non-retail) 비즈니스 면적 비율
- CHAS: 찰스 강 더미 변수 (통로가 하천을 향하면 1; 그렇지 않으면 0)
- NOX: 산화 질소 농도 (천만 분의 1)
- RM:주거 당 평균 객실 수
- AGE: 1940 년 이전에 건축된 자가 소유 점유 비율
- DIS: 5 개의 보스턴 고용 센터까지의 가중 거리
- RAD: 고속도로 접근성 지수
- TAX: 10,000 달러 당 전체 가치 재산 세율
- PTRATIO 도시 별 학생-교사 비율
- B: 1000 (Bk-0.63) ^ 2 여기서 Bk는 도시 별 검정 비율입니다.
- LSTAT: 인구의 낮은 지위
- MEDV: 자가 주택의 중앙값 (1,000 달러 단위)
df = pd.DataFrame(data['data'], columns=data['feature_names'])
df['target'] = data['target']
df.head()
train / test 데이터를 분할 합니다.
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(df.drop('target', 1), df['target'], random_state=SEED)
x_train.shape, x_test.shape
x_train.head()
y_train.head()
모델별 성능 확인을 위한 함수
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import mean_squared_error
my_predictions = {}
my_pred = None
my_actual = None
my_name = None
colors = ['r', 'c', 'm', 'y', 'k', 'khaki', 'teal', 'orchid', 'sandybrown',
'greenyellow', 'dodgerblue', 'deepskyblue', 'rosybrown', 'firebrick',
'deeppink', 'crimson', 'salmon', 'darkred', 'olivedrab', 'olive',
'forestgreen', 'royalblue', 'indigo', 'navy', 'mediumpurple', 'chocolate',
'gold', 'darkorange', 'seagreen', 'turquoise', 'steelblue', 'slategray',
'peru', 'midnightblue', 'slateblue', 'dimgray', 'cadetblue', 'tomato'
]
def plot_predictions(name_, pred, actual):
df = pd.DataFrame({'prediction': pred, 'actual': y_test})
df = df.sort_values(by='actual').reset_index(drop=True)
plt.figure(figsize=(11, 8))
plt.scatter(df.index, df['prediction'], marker='x', color='r')
plt.scatter(df.index, df['actual'], alpha=0.7, marker='o', color='black')
plt.title(name_, fontsize=15)
plt.legend(['prediction', 'actual'], fontsize=12)
plt.show()
def mse_eval(name_, pred, actual):
global my_predictions, colors, my_pred, my_actual, my_name
my_name = name_
my_pred = pred
my_actual = actual
plot_predictions(name_, pred, actual)
mse = mean_squared_error(pred, actual)
my_predictions[name_] = mse
y_value = sorted(my_predictions.items(), key=lambda x: x[1], reverse=True)
df = pd.DataFrame(y_value, columns=['model', 'mse'])
print(df)
min_ = df['mse'].min() - 10
max_ = df['mse'].max() + 10
length = len(df) / 2
plt.figure(figsize=(9, length))
ax = plt.subplot()
ax.set_yticks(np.arange(len(df)))
ax.set_yticklabels(df['model'], fontsize=12)
bars = ax.barh(np.arange(len(df)), df['mse'], height=0.3)
for i, v in enumerate(df['mse']):
idx = np.random.choice(len(colors))
bars[i].set_color(colors[idx])
ax.text(v + 2, i, str(round(v, 3)), color='k', fontsize=12, fontweight='bold', verticalalignment='center')
plt.title('MSE Error', fontsize=16)
plt.xlim(min_, max_)
plt.show()
def add_model(name_, pred, actual):
global my_predictions, my_pred, my_actual, my_name
my_name = name_
my_pred = pred
my_actual = actual
mse = mean_squared_error(pred, actual)
my_predictions[name_] = mse
def remove_model(name_):
global my_predictions
try:
del my_predictions[name_]
except KeyError:
return False
return True
def plot_all():
global my_predictions, my_pred, my_actual, my_name
plot_predictions(my_name, my_pred, my_actual)
y_value = sorted(my_predictions.items(), key=lambda x: x[1], reverse=True)
df = pd.DataFrame(y_value, columns=['model', 'mse'])
print(df)
min_ = df['mse'].min() - 10
max_ = df['mse'].max() + 10
length = len(df) / 2
plt.figure(figsize=(9, length))
ax = plt.subplot()
ax.set_yticks(np.arange(len(df)))
ax.set_yticklabels(df['model'], fontsize=12)
bars = ax.barh(np.arange(len(df)), df['mse'], height=0.3)
for i, v in enumerate(df['mse']):
idx = np.random.choice(len(colors))
bars[i].set_color(colors[idx])
ax.text(v + 2, i, str(round(v, 3)), color='k', fontsize=12, fontweight='bold', verticalalignment='center')
plt.title('MSE Error', fontsize=16)
plt.xlim(min_, max_)
plt.show()
단일 회귀예측 모델 (지난 시간)
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Ridge
from sklearn.linear_model import Lasso
from sklearn.linear_model import ElasticNet
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures
LinearRegression
- 기본 옵션 값을 사용하여 학습합니다.
linear_reg = LinearRegression()
linear_reg.fit(x_train, y_train)
pred = linear_reg.predict(x_test)
mse_eval('LinearRegression', pred, y_test)
Ridge
- 규제 계수인
alpha=0.1
을 적용합니다.
ridge = Ridge(alpha=0.1)
ridge.fit(x_train, y_train)
pred = ridge.predict(x_test)
mse_eval('Ridge(alpha=0.1)', pred, y_test)
Lasso
- 규제 계수인
alpha=0.01
로 적용합니다.
lasso = Lasso(alpha=0.01)
lasso.fit(x_train, y_train)
pred = lasso.predict(x_test)
mse_eval('Lasso(alpha=0.01)', pred, y_test)
ElasticNet
- 규제 계수인
alpha=0.01
,l1_ratio=0.8
을 적용합니다.
elasticnet = ElasticNet(alpha=0.01, l1_ratio=0.8)
elasticnet.fit(x_train, y_train)
pred = elasticnet.predict(x_test)
mse_eval('ElasticNet(alpha=0.1, l1_ratio=0.8)', pred, y_test)
Pipeline 학습
StandardScaler와 ElasticNet의 파이프라인 학습 합니다.
- ElasticNet 모델은 규제 계수인
alpha=0.01
,l1_ratio=0.8
을 적용합니다.
elasticnet_pipeline = make_pipeline(
StandardScaler(),
ElasticNet(alpha=0.01, l1_ratio=0.8)
)
elasticnet_pipeline.fit(x_train, y_train)
elasticnet_pred = elasticnet_pipeline.predict(x_test)
mse_eval('Standard ElasticNet', elasticnet_pred, y_test)
PolynomialFeatures
PolynomialFeatures와 ElasticNet의 파이프라인 학습을 진행합니다.
- PolynomialFeatures는
degree=2
,include_bias=False
로 적용합니다. - ElasticNet 모델은 규제 계수인
alpha=0.1
,l1_ratio=0.2
을 적용합니다.
poly_pipeline = make_pipeline(
PolynomialFeatures(degree=2, include_bias=False),
ElasticNet(alpha=0.1, l1_ratio=0.2)
)
poly_pipeline.fit(x_train, y_train)
poly_pred = poly_pipeline.predict(x_test)
mse_eval('Poly ElasticNet', poly_pred, y_test)
앙상블 (Ensemble)
보팅 (Voting) - 회귀 (Regression)
Voting은 단어 뜻 그대로 투표를 통해 결정하는 방식입니다. Voting은 Bagging과 투표방식이라는 점에서 유사하지만, 다음과 같은 큰 차이점이 있습니다.
- Voting은 다른 알고리즘 model을 조합해서 사용합니다.
- Bagging은 같은 알고리즘 내에서 다른 sample 조합을 사용합니다.
from sklearn.ensemble import VotingRegressor, VotingClassifier
반드시, Tuple 형태로 모델을 정의해야 합니다.
single_models = [
('linear_reg', linear_reg),
('ridge', ridge),
('lasso', lasso),
('elasticnet_pipeline', elasticnet_pipeline),
('poly_pipeline', poly_pipeline)
]
voting_regressor = VotingRegressor(single_models, n_jobs=-1)
voting_regressor.fit(x_train, y_train)
voting_pred = voting_regressor.predict(x_test)
mse_eval('Voting Ensemble', voting_pred, y_test)
보팅 (Voting) - 분류 (Classification)
분류기 모델을 만들때, Voting 앙상블은 1가지의 중요한 parameter가 있습니다.
voting
= {'hard', 'soft'}
hard로 설정한 경우
class를 0, 1로 분류 예측을 하는 이진 분류를 예로 들어 보겠습니다.
Hard Voting 방식에서는 결과 값에 대한 다수 class를 차용합니다.
classification을 예로 들어 보자면, 분류를 예측한 값이 1, 0, 0, 1, 1 이었다고 가정한다면 1이 3표, 0이 2표를 받았기 때문에 Hard Voting 방식에서는 1이 최종 값으로 예측을 하게 됩니다.
soft
soft vote 방식은 각각의 확률의 평균 값을 계산한다음에 가장 확률이 높은 값으로 확정짓게 됩니다.
가령 class 0이 나올 확률이 (0.4, 0.9, 0.9, 0.4, 0.4)이었고, class 1이 나올 확률이 (0.6, 0.1, 0.1, 0.6, 0.6) 이었다면,
- class 0이 나올 최종 확률은 (0.4+0.9+0.9+0.4+0.4) / 5 = 0.44,
- class 1이 나올 최종 확률은 (0.6+0.1+0.1+0.6+0.6) / 5 = 0.4
가 되기 때문에 앞선 Hard Vote의 결과와는 다른 결과 값이 최종 으로 선출되게 됩니다.
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression, RidgeClassifier
models = [
('Logi', LogisticRegression()),
('ridge', RidgeClassifier())
]
voting 옵션에 대하여 지정합니다.
vc = VotingClassifier(models, voting='hard')
배깅(Bagging)
Bagging은 Bootstrap Aggregating의 줄임말입니다.
- Bootstrap = Sample(샘플) + Aggregating = 합산
Bootstrap은 여러 개의 dataset을 중첩을 허용하게 하여 샘플링하여 분할하는 방식
데이터 셋의 구성이 [1, 2, 3, 4, 5 ]로 되어 있다면,
- group 1 = [1, 2, 3]
- group 2 = [1, 3, 4]
- group 3 = [2, 3, 5]
Image('https://teddylee777.github.io/images/2019-12-17/image-20191217015537872.png')
Voting VS Bagging
- Voting은 여러 알고리즘의 조합에 대한 앙상블
- Bagging은 하나의 단일 알고리즘에 대하여 여러 개의 샘플 조합으로 앙상블
대표적인 Bagging 앙상블
- RandomForest
- Bagging
RandomForest
- DecisionTree(트리)기반 Bagging 앙상블
- 굉장히 인기있는 앙상블 모델
- 사용성이 쉽고, 성능도 우수함
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
rfr = RandomForestRegressor()
rfr.fit(x_train, y_train)
rfr_pred = rfr.predict(x_test)
mse_eval('RandomForest Ensemble', rfr_pred, y_test)
주요 Hyperparameter
random_state
: 랜덤 시드 고정 값. 고정해두고 튜닝할 것!n_jobs
: CPU 사용 갯수max_depth
: 깊어질 수 있는 최대 깊이. 과대적합 방지용n_estimators
: 앙상블하는 트리의 갯수max_features
: 최대로 사용할 feature의 갯수. 과대적합 방지용min_samples_split
: 트리가 분할할 때 최소 샘플의 갯수. default=2. 과대적합 방지용
Image('https://teddylee777.github.io/images/2020-01-09/decistion-tree.png', width=600)
튜닝을 할 땐 반드시 random_state
값을 고정시킵니다!
rfr = RandomForestRegressor(random_state=42, n_estimators=1000, max_depth=7, max_features=0.9)
rfr.fit(x_train, y_train)
rfr_pred = rfr.predict(x_test)
mse_eval('RandomForest Ensemble w/ Tuning', rfr_pred, y_test)
부스팅 (Boosting)
Boosting 알고리즘 역시 앙상블 학습 (ensemble learning)이며, 약한 학습기를 순차적으로 학습을 하되, 이전 학습에 대하여 잘못 예측된 데이터에 가중치를 부여해 오차를 보완해 나가는 방식입니다.
다른 앙상블 기법과 가장 다른 점중 하나는 바로 순차적인 학습을 하며 weight를 부여해서 오차를 보완해 나간다는 점인데요. 순차적이기 때문에 병렬 처리에 어려움이 있고, 그렇기 때문에 다른 앙상블 대비 학습 시간이 오래걸린다는 단점이 있습니다.
약한 학습기를 순차적으로 학습을 하되, 이전 학습에 대하여 잘못 예측된 데이터에 가중치를 부여해 오차를 보완해 나가는 방식입니다.
장점
- 성능이 매우 우수하다 (Lgbm, XGBoost)
단점
- 부스팅 알고리즘의 특성상 계속 약점(오분류/잔차)을 보완하려고 하기 때문에 잘못된 레이블링이나 아웃라이어에 필요 이상으로 민감할 수 있다
- 다른 앙상블 대비 학습 시간이 오래걸린다는 단점이 존재
Image('https://keras.io/img/graph-kaggle-1.jpeg', width=800)
대표적인 Boosting 앙상블
- AdaBoost
- GradientBoost
- LightGBM (LGBM)
- XGBoost
GradientBoost
- 성능이 우수함
- 학습시간이 해도해도 너무 느리다
from sklearn.ensemble import GradientBoostingRegressor, GradientBoostingClassifier
gbr = GradientBoostingRegressor(random_state=42)
gbr.fit(x_train, y_train)
gbr_pred = gbr.predict(x_test)
mse_eval('GradientBoost Ensemble', gbr_pred, y_test)
주요 Hyperparameter
random_state
: 랜덤 시드 고정 값. 고정해두고 튜닝할 것!n_jobs
: CPU 사용 갯수learning_rate
: 학습율. 너무 큰 학습율은 성능을 떨어뜨리고, 너무 작은 학습율은 학습이 느리다. 적절한 값을 찾아야함. n_estimators와 같이 튜닝. default=0.1n_estimators
: 부스팅 스테이지 수. (랜덤포레스트 트리의 갯수 설정과 비슷한 개념). default=100subsample
: 샘플 사용 비율 (max_features와 비슷한 개념). 과대적합 방지용min_samples_split
: 노드 분할시 최소 샘플의 갯수. default=2. 과대적합 방지용
gbr = GradientBoostingRegressor(random_state=SEED, learning_rate=0.01)
gbr.fit(x_train, y_train)
gbr_pred = gbr.predict(x_test)
mse_eval('GradientBoosting(lr=0.01)', gbr_pred, y_test)
gbr = GradientBoostingRegressor(random_state=SEED, learning_rate=0.01, n_estimators=1000)
gbr.fit(x_train, y_train)
gbr_pred = gbr.predict(x_test)
mse_eval('GradientBoosting(lr=0.01, est=1000)', gbr_pred, y_test)
gbr = GradientBoostingRegressor(random_state=SEED, learning_rate=0.01, n_estimators=1000, subsample=0.8)
gbr.fit(x_train, y_train)
gbr_pred = gbr.predict(x_test)
mse_eval('GradientBoosting(lr=0.01, est=1000, subsample=0.8)', gbr_pred, y_test)
XGBoost
eXtreme Gradient Boosting
주요 특징
- scikit-learn 패키지가 아닙니다.
- 성능이 우수함
- GBM보다는 빠르고 성능도 향상되었습니다.
- 여전히 학습시간이 매우 느리다
from xgboost import XGBRegressor, XGBClassifier
xgb = XGBRegressor(random_state=SEED)
xgb.fit(x_train, y_train)
xgb_pred = xgb.predict(x_test)
mse_eval('XGBoost', xgb_pred, y_test)
주요 Hyperparameter
random_state
: 랜덤 시드 고정 값. 고정해두고 튜닝할 것!n_jobs
: CPU 사용 갯수learning_rate
: 학습율. 너무 큰 학습율은 성능을 떨어뜨리고, 너무 작은 학습율은 학습이 느리다. 적절한 값을 찾아야함. n_estimators와 같이 튜닝. default=0.1n_estimators
: 부스팅 스테이지 수. (랜덤포레스트 트리의 갯수 설정과 비슷한 개념). default=100max_depth
: 트리의 깊이. 과대적합 방지용. default=3.subsample
: 샘플 사용 비율. 과대적합 방지용. default=1.0max_features
: 최대로 사용할 feature의 비율. 과대적합 방지용. default=1.0
xgb = XGBRegressor(random_state=42, learning_rate=0.01, n_estimators=1000, subsample=0.8, max_features=0.8, max_depth=7)
xgb.fit(x_train, y_train)
xgb_pred = xgb.predict(x_test)
mse_eval('XGBoost w/ Tuning', xgb_pred, y_test)
LightGBM
주요 특징
- scikit-learn 패키지가 아닙니다 (Microsoft 사 개발)
- 부스팅 계열의 알고리즘 입니다.
- 성능이 우수함
특이점
- 기존 부스팅 계열 알고리즘이 가지는 단점인 느린 학습 속도를 개선하였습니다.
from lightgbm import LGBMRegressor, LGBMClassifier
lgbm = LGBMRegressor(random_state=SEED)
lgbm.fit(x_train, y_train)
lgbm_pred = lgbm.predict(x_test)
mse_eval('LGBM', lgbm_pred, y_test)
주요 Hyperparameter
random_state
: 랜덤 시드 고정 값. 고정해두고 튜닝할 것!n_jobs
: CPU 사용 갯수learning_rate
: 학습율. 너무 큰 학습율은 성능을 떨어뜨리고, 너무 작은 학습율은 학습이 느리다. 적절한 값을 찾아야함. n_estimators와 같이 튜닝. default=0.1n_estimators
: 부스팅 스테이지 수. (랜덤포레스트 트리의 갯수 설정과 비슷한 개념). default=100max_depth
: 트리의 깊이. 과대적합 방지용. default=3.colsample_bytree
: 샘플 사용 비율 (max_features와 비슷한 개념). 과대적합 방지용. default=1.0
lgbm = LGBMRegressor(random_state=SEED, learning_rate=0.01, n_estimators=1500, colsample_bytree=0.9, num_leaves=15, subsample=0.8)
lgbm.fit(x_train, y_train)
lgbm_pred = lgbm.predict(x_test)
mse_eval('LGBM w/ Tuning', lgbm_pred, y_test)
Stacking
개별 모델이 예측한 데이터를 기반으로 final_estimator 종합하여 예측을 수행합니다.
- 성능을 극으로 끌어올릴 때 활용하기도 합니다.
- 과대적합을 유발할 수 있습니다. (특히, 데이터셋이 적은 경우)
import sklearn
sklearn.__version__
from sklearn.ensemble import StackingRegressor
stack_models = [
('elasticnet', poly_pipeline),
('randomforest', rfr),
('gbr', gbr),
('lgbm', lgbm),
]
stack_reg = StackingRegressor(stack_models, final_estimator=xgb, n_jobs=-1)
stack_reg.fit(x_train, y_train)
stack_pred = stack_reg.predict(x_valid)
mse_eval('Stacking Ensemble', stack_pred, y_valid)
Weighted Blending
각 모델의 예측값에 대하여 weight를 곱하여 최종 output 계산
- 모델에 대한 가중치를 조절하여, 최종 output을 산출합니다.
- 가중치의 합은 1.0이 되도록 합니다.
final_outputs = {
'elasticnet': poly_pred,
'randomforest': rfr_pred,
'gbr': gbr_pred,
'xgb': xgb_pred,
'lgbm': lgbm_pred,
'stacking': stack_pred,
}
final_prediction=\
final_outputs['elasticnet'] * 0.1\
+final_outputs['randomforest'] * 0.1\
+final_outputs['gbr'] * 0.2\
+final_outputs['xgb'] * 0.25\
+final_outputs['lgbm'] * 0.15\
+final_outputs['stacking'] * 0.2\
mse_eval('Weighted Blending', final_prediction, y_valid)
앙상블 모델을 정리하며
- 앙상블은 대체적으로 단일 모델 대비 성능이 좋습니다.
- 앙상블을 앙상블하는 기법인 Stacking과 Weighted Blending도 참고해 볼만 합니다.
- 앙상블 모델은 적절한 Hyperparameter 튜닝이 중요합니다.
- 앙상블 모델은 대체적으로 학습시간이 더 오래 걸립니다.
- 따라서, 모델 튜닝을 하는 데에 걸리는 시간이 오래 소요됩니다.
검증 (Validation)과 튜닝 (Tuning)
Cross Validation
- Cross Validation이란 모델을 평가하는 하나의 방법입니다.
- K-겹 교차검증(K-fold Cross Validation)을 많이 활용합니다.
K-겹 교차검증
- K-겹 교차 검증은 모든 데이터가 최소 한 번은 테스트셋으로 쓰이도록 합니다. 아래의 그림을 보면, 데이터를 5개로 쪼개 매번 테스트셋을 바꿔나가는 것을 볼 수 있습니다.
[예시]
- Estimation 1일때,
학습데이터: [B, C, D, E] / 검증데이터: [A]
- Estimation 2일때,
학습데이터: [A, C, D, E] / 검증데이터: [B]
Image('https://static.packt-cdn.com/products/9781789617740/graphics/b04c27c5-7e3f-428a-9aa6-bb3ebcd3584c.png', width=800)
K-Fold Cross Validation
from sklearn.model_selection import KFold
n_splits = 5
kfold = KFold(n_splits=n_splits, random_state=SEED)
df.head()
X = np.array(df.drop('target', 1))
Y = np.array(df['target'])
lgbm_fold = LGBMRegressor(random_state=SEED)
i = 1
total_error = 0
for train_index, test_index in kfold.split(X):
x_train_fold, x_valid_fold = X[train_index], X[test_index]
y_train_fold, y_valid_fold = Y[train_index], Y[test_index]
lgbm_pred_fold = lgbm_fold.fit(x_train_fold, y_train_fold).predict(x_valid_fold)
error = mean_squared_error(lgbm_pred_fold, y_valid_fold)
print('Fold = {}, prediction score = {:.2f}'.format(i, error))
total_error += error
i+=1
print('---'*10)
print('Average Error: %s' % (total_error / n_splits))
Hyperparameter 튜닝
- hypterparameter 튜닝시 경우의 수가 너무 많습니다.
- 따라서, 우리는 자동화할 필요가 있습니다.
sklearn 패키지에서 자주 사용되는 hyperparameter 튜닝을 돕는 클래스는 다음 2가지가 있습니다.
- RandomizedSearchCV
- GridSearchCV
적용하는 방법
- 사용할 Search 방법을 선택합니다.
- hyperparameter 도메인을 설정합니다. (
max_depth
,n_estimators
..등등) - 학습을 시킨 후, 기다립니다.
- 도출된 결과 값을 모델에 적용하고 성능을 비교합니다.
RandomizedSearchCV
- 모든 매개 변수 값이 시도되는 것이 아니라 지정된 분포에서 고정 된 수의 매개 변수 설정이 샘플링됩니다.
- 시도 된 매개 변수 설정의 수는
n_iter
에 의해 제공됩니다.
주요 Hyperparameter (LGBM)
random_state
: 랜덤 시드 고정 값. 고정해두고 튜닝할 것!n_jobs
: CPU 사용 갯수learning_rate
: 학습율. 너무 큰 학습율은 성능을 떨어뜨리고, 너무 작은 학습율은 학습이 느리다. 적절한 값을 찾아야함. n_estimators와 같이 튜닝. default=0.1n_estimators
: 부스팅 스테이지 수. (랜덤포레스트 트리의 갯수 설정과 비슷한 개념). default=100max_depth
: 트리의 깊이. 과대적합 방지용. default=3.colsample_bytree
: 샘플 사용 비율 (max_features와 비슷한 개념). 과대적합 방지용. default=1.0
params = {
'n_estimators': [200, 500, 1000, 2000],
'learning_rate': [0.1, 0.05, 0.01],
'max_depth': [6, 7, 8],
'colsample_bytree': [0.8, 0.9, 1.0],
'subsample': [0.8, 0.9, 1.0],
}
from sklearn.model_selection import RandomizedSearchCV
n_iter
값을 조절하여, 총 몇 회의 시도를 진행할 것인지 정의합니다.
(회수가 늘어나면, 더 좋은 parameter를 찾을 확률은 올라가지만, 그만큼 시간이 오래걸립니다.)
clf = RandomizedSearchCV(LGBMRegressor(), params, random_state=42, cv=3, n_iter=25, scoring='neg_mean_squared_error')
clf.fit(x_train, y_train)
clf.best_score_
clf.best_params_
lgbm_best = LGBMRegressor(n_estimators=2000, subsample=0.8, max_depth=7, learning_rate=0.01, colsample_bytree=0.8)
lgbm_best.fit(x_train, y_train)
lgbm_best_pred = lgbm_best.predict(x_test)
mse_eval('RandomSearch LGBM', lgbm_best_pred, y_test)
GridSearchCV
- 모든 매개 변수 값에 대하여 완전 탐색을 시도합니다.
- 따라서, 최적화할 parameter가 많다면, 시간이 매우 오래걸립니다.
params = {
'n_estimators': [500, 1000],
'learning_rate': [0.1, 0.05, 0.01],
'max_depth': [7, 8],
'colsample_bytree': [0.8, 0.9],
'subsample': [0.8, 0.9,],
}
from sklearn.model_selection import GridSearchCV
grid_search = GridSearchCV(LGBMRegressor(), params, cv=3, n_jobs=-1, scoring='neg_mean_squared_error')
grid_search.fit(x_train, y_train)
abs(grid_search.best_score_)
grid_search.best_params_
lgbm_best = LGBMRegressor(**grid_search.best_params_)
lgbm_best.fit(x_train, y_train)
lgbm_best_pred = lgbm_best.predict(x_test)
mse_eval('GridSearch LGBM', lgbm_best_pred, y_test)
댓글남기기