[ML] 교차검증, cross-validation
교차 검증의 필요성
val
만약 위와 같이 train과 val set을 고정하고 학습한다면 학습과정에서 valset을 기준으로 학습 및 파라미터 튜닝이 진행 되기 때문에 val set에 과적합되는 경우가 생기게된다. 이를 해결하고자하는 것이 바로 교차검증이다.
장점
- 특정 val set에 과적합되는 것을 방지할 수 있다.
- 최대한 모든 데이터를 활용가능하다.
단점
- 학습의 속도가 k배로 늘어난다.
1. KFold
데이터를 k 등분하고 각각 k-1개의 데이터를 trainset으로 나머지 하나의 데이터를 valset으로 활용하는 방법이이다.
from sklearn.model_selection import StratifiedKFold, KFold
from sklearn.metrics import mean_absolute_error
kf = KFold(n_splits=5, shuffle=True, random_state=722)
pred_list = []
mae_list = []
for fold,(train_index, val_index) in enumerate(kf.split(X)):
print(f'***********{fold+1}th fold start***********')
x_train, x_val, y_train, y_val = X.loc[train_index], X.loc[val_index], y.loc[train_index], y.loc[val_index]
lgb = lightgbm.LGBMRegressor(boosting_type='gbdt',
n_estimators=1000, random_state=722, learning_rate=0.05, categorical_feature=[0])
lgb.fit(x_train, y_train,
eval_set=(x_val,y_val),
eval_metric='mae', verbose=False, early_stopping_rounds=100)
pred = lgb.predict(x_val)
result = mean_absolute_error(pred,y_val)
mae_list.append(result)
print(f'mae : {result:.4f}', end='\n\n')
print(f'mean mae {np.mean(mae_list):.4f}')
***********1th fold start***********
mae : 1.6950
***********2th fold start***********
mae : 1.6058
***********3th fold start***********
mae : 1.5267
***********4th fold start***********
mae : 1.5838
***********5th fold start***********
mae : 1.5302
mean mae 1.5883
kf = KFold(n_splits=5, shuffle=True, random_state=722)
- n_splits : k
- shuffle=True (섞을까?)
위와 같이 Kfold 객체를 생성하고
for fold,(train_index, val_index) in enumerate(kf.split(X)):
split(x) 메소드로 각 인덱스를 받게 된다
이후 위의 코드처럼 학습을 진행하면된다.
2. StratifiedKFold
kfold를 하더라도 어느 fold의 트레인셋에 특정 class의 값이 편중되어있다면 해당클래스에 과적합될 것이다. 이를 방지하기 위하여 StratifiedKFold를 사용한다.
데이터를 k등분 한다는 점은 kfold와 같지만 StratifiedKFold는 범주형변수의 비율에 맞게 fold들을 반환한다.
예측하려는 변수가 범주형이라면 타겟을 fold를 나누는데에 활용하면 될 것이고
예측하려는 변수가 연속형이라면 타겟의 차이가 크게 나타나는 범주형변수나 구간화를 진행하여 활용하면 된다.
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=722)
for fold,(train_index, val_index) in enumerate(kf.split(X)):
print(f'***********{fold+1}th fold start***********')
x_train, x_val, y_train, y_val = X.loc[train_index], X.loc[val_index], y.loc[train_index], y.loc[val_index]