#!/usr/bin/env python3


scikit-learn에서의 cross-validation(교차검증)


scikit-learn에서 교차 검증은 model_selection 모듈cross_val_score 함수로 구현되어 있음


1. iris 데이터셋에 cross-validation을 간단하게 적용하기

iris 데이터셋에 LogisticRegression을 평가해보면

LogisticRegression 이전 포스팅 참조하기: [1]Logistic Regression[1], [2]Logistic Regression[2]


# library import

from sklearn.model_selection import cross_val_score

from sklearn.datasets import load_iris

from sklearn.linear_model import LogisticRegression


# dataset

iris = load_iris()

logreg = LogisticRegression()


scores = cross_val_score(logreg, iris.data, iris.target, cv=5) # model, train, target, cross validation


print('cross-val-score \n{}'.format(scores))

print('cross-val-score.mean \n{:.3f}'.format(scores.mean()))


5겹 교차검증 결과와 평균


>> 교차 검증 평균값으로 우리는 이 모델의 정확도가 대략 96%일 것으로 기대할 수 있음

5겹 교차 검증이 만든 5개의 값을 모두 보면 100%에서 90%까지 폴드에 따라 비교적 차이가 큼

이는 모델이 훈련에 사용한 폴드에 매우 의존적이거나 데이터셋이 작기 때문일 수 있음



교차 검증의 장점은 train_test_split와 비교해보면

train_test_split는 데이터를 무작위로 나눔. 데이터를 무작위로 나눌 때

훈련 세트 ==>  분류하기 어려운 샘플

테스트세트 ==> 분류하기 쉬운 샘플

테스트 세트의 정확도는 비현실적으로 높게 나올 것입니다. 

반대의 경우라면 테스트 세트의 정확도는 비현실적으로 낮게 나옴


그러나 교차 검증을 사용하면 테스트 세트에 각 샘플이 정확하게 한번씩 들어가고

각 샘플은 폴드 중 하나에 속하며 각 폴드는 한번씩 테스트 세트가 됨 

그렇기 때문에 교차 검증의 점수를 높이기 위해서는 데이터 셋에 있는 모든 샘플에 대해 모델이 잘 일반화 되어야 함


데이터를 여러개로 나누면 모델이 훈련 데이터에 얼마나 민감한지 알 수가 있음 

iris데이터셋에서 90%~ 100%의 정확도를 얻음. 최악의 경우와 최선의 경우를 짐작할 수 있음


교차 검증의 주요 단점연산 비용이 늘어남

모델을 k개 만들어야 하므로 데이터를 한 번 나눴을때보다 대략 k배 더 느림



2. 계층별 k-겹 교차 검증과 그 외 전략들


# load library

import matplotlib.pyplot as plt

import matplotlib

from sklearn.datasets import load_iris

from sklearn.linear_model import LogisticRegression

from sklearn.model_selection import cross_val_score

import numpy as np


# data load

iris = load_iris()


print('iris label \n{}'.format(iris.target))

print('''iris label's bin \n{}'''.format(np.bincount(iris.target)))

iris label과 bin


>>첫번째 1/3은 클래스 0, 두번째 1/3은 클래스1 마지막 1/3은 클래스2 임을 확인할 수 있음

첫번째 폴드는 클래스 0만 가지고 있으므로, 첫 번째 반복에서 테스트세트는 클래스 0만을, 훈련세트는 클래스 1과 2만을 가지게 됨 

세번의 반복 모두 훈련 세트와 테스트 세트의 클래스가 다르므로 데이터셋에서 3-겹 교차 검증의 정확도는 0이 됨



단순한 k-겹 교차검증에는 문제가 있으니 stratified k-fold cross-validation계층별 k-겹 교차 검증을 사용함


# library import

import mglearn


# matplotlob 설정

matplotlib.rc('font', family='AppleGothic'# 한글출력

plt.rcParams['axes.unicode_minus']=False # 축 -


mglearn.plots.plot_stratified_cross_validation()

plt.show()

클래스 레이블 순서대로 정렬된 데이터에서 기본 교차 검증과 계층별 교차 검증 비교


계층별 교차 검증은 폴드 안의 클래스 비율이 데이터셋의 클래스 비율과 같도록 데이터를 나눔

예를 들어 샘플의 90%가 클래스 A이고 10%가 클래스 B에 속한다면, 계층별 교차 검증은 각 폴드에 클래스 A샘플이 90%, 클래스 B 샘플이 10%가 되도록 만듬



2. 교차 검증 상세 옵션


그러나 scikit-learn에서는 cv 매개변수에 교차 검증 분할기cross-vailidation splitter를 전달함으로써 데이터를 분할할 때 더 세밀하게 제어할 수 있음

대부분의 경우 회귀에서는 k-겹 교차 검증, 분류에서는 계층별 k-겹 교차검증의 기본값이 잘 작동함


하지만 조금 다른 전략이 필요할 때가 있음. 예를 들어 다른사람의 결과를 재현하기 위해 분류 데이터셋에 기본 k-겹 교차 검증을 사용해야 할때

이렇게 하려면 먼저 model_selection에서 KFold 분할기를 임포트하고 원하는 폴드 수를 넣어 객체를 생성해야 함


# library import

from sklearn.model_selection import KFold


kfold = KFold(n_splits=5) # KFold 객체 생성

logreg = LogisticRegression() # 모델 객체 생성


for n in [3, 5]:

    kfold = KFold(n_splits=n)

    scores = cross_val_score(logreg, iris.data, iris.target, cv=kfold)

    print('n_splits={}, cross validation score: {}'.format(n, scores))

n_splits에 따른 교차 검증 테스트 점수

>> n_splits=3일 때 각 폴드는 iris 데이터셋의 클래스 중 하나에 대응하므로 아무것도 학습할 수가 없음

계층별 폴드를 만드는 대신 이문제를 해결하는 방법은 

데이터를 섞어서 샘플의 순서를 랜덤하게 만드는것(KFold의 shuffle 매개변수True)


데이터를 섞을 때 random_state를 고정해서 똑같은 작업을 재현할 수있음

그렇지 않으면 cross_val_score를 실행할 때마다 폴드가 바뀌어 매번 결과가 달라짐


for n in [3, 5]:

    kfold = KFold(n_splits=n, shuffle=True, random_state=0)

    scores = cross_val_score(logreg, iris.data, iris.target, cv=kfold)

    print('n_splits={}, cross validation score: {}'.format(n, scores))


shuffle과 random_stat매개변수를 조정한 교차 검증 테스트 점수

>> n_splits에 상관없이 결과가 유의미하다는 것을 확인할 수가 있음



'모델 평가와 성능 향상 > 교차 검증' 카테고리의 다른 글

다양한 교차 검증 방법  (0) 2018.04.03
cross-validation  (0) 2018.04.02

+ Recent posts