소소하지만 소소하지 않은 개발 공부/머신 러닝 교과서

6.2 k-겹 교차 검증을 사용한 모델 성능 평가

still..epochs 2022. 12. 14. 12:11

* 본 포스팅은 머신러닝교과서를 참조하여 작성되었습니다.

* https://github.com/rickiepark/python-machine-learning-book-3rd-edition

 

GitHub - rickiepark/python-machine-learning-book-3rd-edition: <머신 러닝 교과서 3판>의 코드 저장소

<머신 러닝 교과서 3판>의 코드 저장소. Contribute to rickiepark/python-machine-learning-book-3rd-edition development by creating an account on GitHub.

github.com

 

모델이 너무 간단하면 과소적합(높은 편향)이 문제가 되고 너무 복잡하면 훈련 데이터에 과대 적합(높은 분산)이 될 수 있다. 적절한 편향-분산 트레이드오프를 찾으려면 모델을 주의 깊게 형가해야 한다.

 

이 절에서는 보편적인 교차 검증 기법인 홀드아웃 교차 검증(holdout cross-validatioin)과 k-겹 교차 검증(k-fold cross-validation) 을 배워보자.

 

이 방법들은 모델의 일반화 성능, 즉 처음 본 데이터에 모델이 얼마나 잘 동작하는지 신뢰할 만한 추정을 하도록 도와준다.

 

6.2.1 홀드아웃 방법

모델 선택에 홀드아웃 방법을 사용하는 가장 좋은 방법은 데이터를 훈련 데이터셋, 검증 데이터셋, 테스트 데이터셋 세 개의 부분으로 나누는 것이다.

 

훈련 데이터셋은 여러 가지 모델을 훈련하는 데 사용한다.

검증 데이터셋에 대한 성능은 모델 선택에 사용한다.

 

훈련과 모델 선택 단계에서 모델이 만나지 못한 테스트 데이터셋을 분리했기 때문에 새로운 데이터에 대한 일반화 능력을 덜 편향되게 추정 할 수 있다.

 

홀드아웃 교차 검증

 

6.2.2 k-겹 교차 검증

k-겹 교차 검증에는 중복을 허용하지 않고 훈련 데이터셋을 k개의 폴드(fold)로 랜덤하게 나눈다. k-1개의 폴드로 모델을 훈련하고 나머지 하나의 폴드로 성능을 평가한다. 이 과정을 k번 반복하여 k개의 모델과 성능 추정을 얻는다. 그다음 서로 다른 독립적인 폴드에서 얻은 성능 추정을 기반으로 모델의 평균 성능을 계산한다.

k-겹 교차 검증

위 그림은 k=10일 때 k-겹 교차 검증의 개념을 요약한 것이다. 훈련 데이터는 열 개의 폴드로 나누어지고 열 번의 반복동안 아홉 개의 폴드는 훈련에, 한 개의 폴드는 모델 평가를 위해 사용된다.

 

또한, 각 폴드의 추정 성능을 사용하여 모델의 평균 성능을 계산한다. 경험적으로 보았을 때 k-겹 교차 검증에서 좋은 기본값은 k=10 이다.

 

기본 k-겹 교차 검증 방법보다 좀 더 향상된 방법은 계층적 k-겹 교차 검증(stratified k-fold cross-validation)이다. 좀 더 나은 편향과 분산 추정을 만든다. 특히 클래스 비율이 동등하지 않을 때이다.

 

계층적 교차 검증은 각 폴드에서 클래스 비율이 전체 훈련 데이터셋에 있는 클래스 비율을 대표하도록 유지한다.

import numpy as np
from sklearn.model_selection import StratifiedKFold

kfold = StratifiedKFold(n_splits=10).split(X_train, y_train)
scores = []
for k, (train, test) in enumerate(kfold):
    pipe_lr.fit(X_train[train], y_train[train])
    score = pipe_lr.score(X_train[test], y_train[test])
    scores.append(score)
    print('폴드: %2d, 클래스 분포: %s, 정확도: %.3f' % (k+1, np.bincount(y_train[train]), score))
    
    
>>  폴드:  1, 클래스 분포: [256 153], 정확도: 0.935
    폴드:  2, 클래스 분포: [256 153], 정확도: 0.935
    폴드:  3, 클래스 분포: [256 153], 정확도: 0.957
    폴드:  4, 클래스 분포: [256 153], 정확도: 0.957
    폴드:  5, 클래스 분포: [256 153], 정확도: 0.935
    폴드:  6, 클래스 분포: [257 153], 정확도: 0.956
    폴드:  7, 클래스 분포: [257 153], 정확도: 0.978
    폴드:  8, 클래스 분포: [257 153], 정확도: 0.933
    폴드:  9, 클래스 분포: [257 153], 정확도: 0.956
    폴드: 10, 클래스 분포: [257 153], 정확도: 0.956

 

사이킷런은 k-겹 교차 검증 함수를 제공한다. 좀 더 간단하게 계층별 k-겹 교차 검증을 사용하여 모델을 평가할 수 있다.

from sklearn.model_selection import cross_val_score

scores = cross_val_score(estimator=pipe_lr,
                         X = X_train,
                         y = y_train,
                         cv = 10,
                         n_jobs = 1)

print('CV 정확도 점수: %s' % scores)

print('CV 정확도: %.3f +/- %.3f' % (np.mean(scores), np.std(scores)))

>> CV 정확도 점수: [0.93478261 0.93478261 0.95652174 0.95652174 0.93478261 0.95555556
				   0.97777778 0.93333333 0.95555556 0.95555556]
                   
   CV 정확도: 0.950 +/- 0.014

 

cross_val_score 함수의 아주 유용한 기능은 각 폴드의 평가를 컴퓨터에 있는 복수 개의 CPU 코어에 분산할 수 있다.

n_jobs = 2로 설정하면 두 개의 CPU 코어에 교차 검증을 10회씩 분산할 수 있다. n_jobs=-1로 설정하면 컴퓨터에 설정된 모든 CPU 코어를 사용하여 병렬 처리한다.