Programming & Machine Learning/풀어쓰는 머신러닝

교차검증(Cross Validation)을 통한 모델 평가방법

Yamarae 2017. 8. 11. 02:59

모델 평가

머신러닝 모델을 학습하는 데 있어서 중요한 점 중 하나는, 새로운 데이터셋에 대한 반응하는 모델의 성능을 추정하는 것이다.
만약 새로운 데이터셋이 들어왔을 때 학습된 모델이 얼마나 예측이나 분류를 잘 수행하는지에 대한 예상이 필요하다.
우리가 학습한 모델이 새로운 데이터에 대한 결과의 예상이라면 우리는 그 모델이 얼마나 잘 예상할지에 대한 예상이 필요하다.

정확한 용어로 얘기하자면, 모델의 일반화 오차에 대해 신뢰할만한 추정치를 구할 수 있게 해주는 방법이 필요하다는 것이다.

그 방법으로는 일반적으로 크게 두가지, 홀드아웃(holdout) 교차검증과 k-fold 교차검증의 방법이 있다.

1. 홀드아웃 교차검증 방법

가장 보편적인 모델의 성능 테스트 방법은, 원 데이터를 훈련데이터와 테스트데이터 두개로 나누는 것이다.
훈련데이터로 모델을 학습하고, 테스트 데이터로 모델의 성능을 증가시키는 선택을 반복하게 된다.
하지만 모델을 선택하는 동안 동일한 테스트 데이터를 계속 재사용한다면, 이 테스트 데이터는 테스트데이터로써의
효용가치가 떨어지고, 훈련데이터화 될 것이다. 결국 데이터는 오버피팅 된다.

하지만 홀드아웃 메서드를 사용하면 데이터를 세 부분으로 나누게 된다.
처음의 모델 학습에서 분리된 훈련 데이터와 테스트 데이터, 즉 ((훈련데이터, 검증데이터), 테스트데이터) 세 개로 나뉜다.
여기서의 훈련 데이터는 말 그대로 훈련 데이터이고, 검증 데이터에 대한 성능을 높이는 작업을 학습에서 진행한다.
그리고 테스트 데이터를 이용하여 최종 성능을 추정하게 된다.

홀드아웃 교차검증의 단점은, 데이터를 위와 같이 나눈 방식 자체가 성능 추정에 민감한 영향을 미친다는 것이다.
만약 데이터셋 전체가 개수가 크지 않다면, 이러한 분할은 치명적일 수 있다.
즉 홀드아웃 셋을 만들어 내는 것 자체에 대단한 신경을 써야한다는 것이다.

2. k-fold 교차검증 방법

k-fold 교차검증은 조금 더 강인한 성능추정 기법이다.
분류기 성능 측정의 통계적 신뢰도를 높이기 위해서, resampling 방법을 사용한다.

먼저 데이터를 k개의 데이터로 등분한다. 분리된 k개의 subset중에 k-1개를 훈련 데이터로 사용하고
(샘플링의 방법은 simple random, systematic, stratified, First N, cluster등이 있음.)
1개의 subset을 테스트 데이터로 사용한다. 여기서 비복원 추출의 개념으로, 한번 테스트로 선택된 subset 데이터는
다시 선택되지 않는다. 물론 k-fold와 홀드아웃 교차검증을 섞어서 사용할 수도 있다.
그리고 당연하게도, k등분 된 k-fold 검정에서의 iterate 횟수는 k번이다. (비복원으로 모든 경우의 수를 하는 갯수)

k-fold의 장점은 모든 데이터를 training과 test에 쓸 수 있다는 점이다. 또한 오버피팅의 염려도 크지 않다.
하지만 시간이 다소 오래걸린다는 단점이 존재한다.
k=n 으로 설정하여 1개의 샘플을 테스트셋으로 두어 샘플의 숫자만큼 반복측정을 하는,
leave-one-out(혹은 jackknife 기법)기법과 같은 극단적인 방법으로 실행할 때는 더더욱 그렇다.

보통 k-fold는 일반화 성능을 만족시키는 최적의 하이퍼 파라미터를 구하기 위한 모델 튜닝에 사용된다는 것이 가장 중요하다.

위에서 잠시 언급한 층화 추출(stratified) 등으로 k-fold를 샘플링하게 되면 이 알고리즘은 조금 더 개선이 가능하다.
그것을 층화 k-fold 교차검증(Stratified K-fold Cross Validation)이라고 한다.

k-fold 교차검증을 파이썬에서 사용하기

from sklearn.cross_validation import cross_val_score

scores = cross_val_score(estimator=pipe_lr, 
                         X=X_train, 
                         y=y_train, 
                         cv=10,
                         n_jobs=1)
print('CV accuracy scores: %s' % scores)
print('CV accuracy: %.3f +/- %.3f' % (np.mean(scores), np.std(scores)))