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