#!/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

+ Recent posts