Cross-validation(교차검증)

 

  • 일반화 성능을 평가하는데에 트레인/테스트 데이터로 한 번 나누는 것보다 더 안정적이고 뛰어난 통계적 평가 방법

  • 교차 검증에서는 데이터를 여러번 반복해서 나누고 여러 모델을 학습함

  • 대표적으로 k-fold cross-validation(k-겹 교차검증)

 

1.1 scikit-learn의 교차검증(KFold)

  • model_selection 모듈의 cross_val_score 함수로 구현
from sklearn import datasets
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression


# 1. load iris
iris = datasets.load_iris()


# 2. create model object
logreg = LogisticRegression()


# 3. cross-validation
scores = cross_val_score(logreg, iris.data, iris.target)
print("cross validation scores : {}".format(scores))
# 결과 : cross validation scores : [0.96078431 0.92156863 0.95833333]


# 3.1 cross-validation: k=5
scores_K5 = cross_val_score(logreg, iris.data, iris.target,cv =5)
print("cross validation scores : {}".format(scores_K5))
# 결과 :cross validation scores : [1.   0.96666667 0.93333333 0.9   1.   ]


# 3.1.1 cross-validation: k=5  -> 평균
print("cross validation scores : {:.2f}".format(scores_K5.mean()))
# 결과 : cross validation scores : 0.96

- 3. 과 3.1 은 cv의 값이 다르기 때문에 cv값에 따라 폴드되어 검증하기 때문에 결과가 k=5일 때, scores가 5개가 나오게 된다.

 

 

 

1.2 교차 검증 시 주의 사항

  • 단순한 k겹 교차 검증은 데이터가 랜덤하지 않은 경우, 특히 분류 문제에서 클래스 별로 구성된 데이터일 때, 적용에 주의해야 함
  • 위와 같은 데이터 형태일 때는 model_selection 모듈 내의 KFold()를 사용하여 기본형 k겹 교차검증을 보완할 수 있다.

* K-Fold : 검증을 하기 위해 데이터를 분리하는데 train, test로 분류하지 않고 train -> train + validation(검증) 으로 나누어서 검증을 할 수 있다. 그렇지만 데이터의 수가 작은 경우에 제대로 할 수 없기 때문에 사용하게 된다.

예를 들어 k=5를 선택한다면,

1) 데이터를 비슷한 크기의 부분집합 5개로 나눔

2) 첫번째 모델은 train : [ 1 2 3 4 ] test : [ 5 ],  두번째 모델은 train : [ 1 2 3 5 ]  test : [ 4 ]  ....

3) 이와 같이 5개의 정확도 값을 얻게됨

from sklearn.model_selection import KFold

# 1.1 KFold default parameter
kfold = KFold(n_splits=3)

# 1.1.1 socore
print("cross validation score : {}".format(cross_val_score(logreg, iris.data, iris.target, cv = kfold)))
# 결과: cross validation score : [0. 0. 0.]


# 1.2 KFold shuffle
kfold1 = KFold(n_splits=3, shuffle=True, random_state=0)

# 1.2.1 score
print("cross validation score : {}".format(cross_val_score(logreg, iris.data, iris.target, cv = kfold1)))
# 결과 : cross validation score : [0.9  0.96 0.96]

- 1.1 에서 iris 데이터는 품종별로 데이터가 정리되어 있다. 원하는 것이 품종(class) 인데 이것을  n_splits = 3이 되면 클래스가 분리되어 사라지게 되므로 1.1.1의 결과가 0 이 나온다

- 이런 점을 방지하기 위해 shuffle을 해준다.

 

 

1.3 임의분할 계층별 교차검증

  • 매우 유연한 교차 검증 전략
  • train_size / test_size로 데이터 임의 분할(중복 없음)
  • 이 분할은 n_split 횟수만큼 반복됨
  • 예를 들어, 샘플이 10개인 데이터에서 train_size=6, test_size=2로 설정하면, 2개의 샘플은 사용되지 않음
  • 계층별 즉, 클래스의 존재 비율에 따라 추출하여 검증

 

from sklearn.model_selection import StratifiedShuffleSplit
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt


# 1. StratifiedShuffleSplit 이용 (계층 이용)
stratified_shuffle_split = StratifiedShuffleSplit(train_size=0.7, test_size=0.3, n_splits=10, random_state=0)


# 2. 교차검증 점수
# 로지스틱 모델 사용하며, cv : 폴드 수( n_splits = 10 이여서 10이 들어가게 됨)
score = cross_val_score(logreg, iris.data, iris.target, cv=stratified_shuffle_split)


# 3. 점수 확인
print("score : {}".format(score))
# n_splits = 10개여서 10번의 횟수만큼 반복됨 
# output : score : [0.97777778 0.91111111 0.95555556 0.91111111 0.95555556 0.93333333 0.97777778 0.95555556 0.97777778 1.        ]


# 4. 데이터 확인 방법
X = iris.data
y = iris.target

for train_index, test_index in stratified_shuffle_split.split(X,y):
    print("train:",train_index,"\n","test:",test_index)
    X_train,X_test = X[train_index],X[test_index]
    y_train,y_test = y[train_index],y[test_index]
# 결과는 train과 test가 10개씩 각각 안엔 위에서 정한 train 70%, test 30% 씩 무작위로 섞여있다.
    

# 5. 교차검증 확인
sss = cross_val_score(logreg, iris.data, iris.target, cv = stratified_shuffle_split)
sss.mean()  # 0.9555555555555555


# y_train 데이터 확인
np.bincount(y_train) # 총 카운트 array([35, 35, 35], dtype=int64)
plt.hist(y_train) # 그래프 확인

 

- 그래프의 결과를 보면 35개씩 세개의 클래스가 동일한 값을 가진 것을 확인할 수 있다. 임의 계층으로 분류할 때 클래스의 비율로 하기 때문에 (iris의 품종 클래스 비율 1 : 1 : 1) 동일한 값이 나오게 된 것이다.

 

 

+ Recent posts