#!/usr/bin/env python3
nested cross-validation
GridSearchCV를 사용할 때 데이터를 train set와 test set로 한 번만 나누기 때문에, 결과가 불안정하고 테스트 데이터의 분할에 크게 의존합니다.
이런 문제를 해결하기 위해 cross-validation 방식을 사용할 수 있습니다.
이를 nested cross-validation중첩교차검증이라 합니다.
nested cross-validation에서는 바깥쪽 루프에서 데이터를 train set와 test set로 나눈 여러개의 fold폴드를 만듭니다. 각 fold의 train set에 대해 grid search를 실행하며, 이 때 바깥쪽 루프에서 분할된 fold의 train set마다 optimal parameter가 다를 수 있습니다.
그런 다음 바깥쪽에서 분할된 fold의 test set의 점수를 optimal parameter 설정을 사용해 각각 측정합니다.
이 방법은 모델이나 parameter 설정이 아닌 테스트 점수의 목록을 만들어주고, grid search를 통해 찾은 optimal parameter가 모델을 얼마나 잘 일반화시키는지 알려줍니다.
새로운 데이터에 적용할 모델을 만드는 것이 아니니, nested cross-validation은 미래의 데이터에 적용하기 위한 예측 모델을 찾는데는 거의 사용하지 않습니다. 그러나 특정 데이터셋에서 주어진 모델이 얼마나 잘 일반화되는지 평가하는데 유용한 방법입니다.
GridSearchCV의 객체를 모델로 삼아 cross_val_score 함수를 호출하면 됩니다.
# library import
from sklearn.datasets import load_wine
from sklearn.model_selection import GridSearchCV, cross_val_score
from sklearn.svm import SVC
# datasets
wine = load_wine()
# create object
values = [0.001, 0.01, 0.1, 1, 10, 100]
param_grid = {'C':values, 'gamma':values}
svc= SVC()
# grid search
grid_search = GridSearchCV(svc, param_grid, cv=5)
scores = cross_val_score(grid_search, wine.data, wine.target, cv=5)
print('교차 검증 점수 ==> {}'.format(scores))
print('교차 검증 평균 점수 ==> {:.3f}'.format(scores.mean()))
# 교차 검증 점수 ==> [0.75675676 0.66666667 0.75 0.8 0.88235294]
# 교차 검증 평균 점수 ==> 0.771
>> SVC는 wine 데이터셋에서 평균 교차 정확도가 77.1%라고 말할 수 있습니다.
여기에서 안쪽 루프와 바깥쪽 루프에 각각 stratified 5 cross-validation을 사용했고
param_grid의 매개변수 조합은 6x6 = 36이고 이 때 만들어지는 모델은 36 x 5 x 5 = 900이므로
중첩 교차 검증은 연산 비용이 매우 큽니다
여기에서 안쪽 루프와 바깥쪽 루프에 같은 교차 검증 분할기를 사용했으며, 꼭 같을 필요는 없습니다.
위의 한 줄의 코드는 다음과 같이 표현할 수 있습니다.
# library import
import numpy as np
def nested_cv(x, y, inner_cv, outer_cv, Classifier, parameter_grid):
outer_scores = []
for train_samples, test_samples in outer_cv.split(x, y):
best_params = {}
best_score = -np.inf
for parameters in parameter_grid:
cv_scores = []
for inner_train, inner_test in inner_cv.split(
x[train_samples], y[train_samples]):
clf = Classifier(**parameters) # **kwargs:
clf.fit(x[inner_train], y[inner_train])
score = clf.score(x[inner_test], y[inner_test])
cv_scores.append(score)
mean_score = np.mean(cv_scores)
if mean_score > best_score:
best_score = mean_score
best_params = parameters
clf = Classifier(**best_params)
clf.fit(x[train_samples], y[train_samples])
outer_scores.append(clf.score(x[test_samples], y[test_samples]))
return np.array(outer_scores)
# library import
from sklearn.model_selection import ParameterGrid, StratifiedKFold
scores = nested_cv(wine.data, wine.target, StratifiedKFold(5), StratifiedKFold(5), SVC, ParameterGrid(param_grid))
print('교차 검증 점수 ==> {}'.format(scores))
# cross-validation score ==> [0.64864865 0.66666667 0.63888889 0.68571429 0.79411765]
'모델 평가와 성능 향상 > 그리드 서치' 카테고리의 다른 글
asymmetric parameter with grid search (0) | 2018.04.05 |
---|---|
cross-validation result analysis (2) | 2018.04.05 |
parameter overfitting (0) | 2018.04.04 |
simple grid search (1) | 2018.04.03 |