본문 바로가기

파이썬/모델 성능평가

쉽게 알아보는 K겹 교차검증(K-fold cross validation) 개념과 코드

K겹 교차검증은 통계학에서 모델을 평가하는 방법 중 하나이다. 딥러닝, 머신러닝에서도 모델 평가 방법으로 많이 사용된다. 보통 분류 모델 성능 평가에 StratifiedKFold를 많이 사용한다.

 

 

 

k'겹'이라는게 무슨 말인가.. 초보자의 입장에서는 잘 와닿지 않는다.


기본적으로 머신러닝으로 모델을 만들 때 데이터를 train set과 test set으로 나눈다. 이때 test set은 모델 학습에는 사용되지 않고 만들어진 모델이 잘 학습되었는지, 오버피팅 되지는 않았는지를 평가하기 위해서 사용하는 데이터셋이다. 보통 train_test 비율은 7:3 혹은 8:2로 나눈다.

 

 

k겹 교차검증을 하지 않으면 train set과 test set을 딱 한 번만 나눠서 모델링을 하는데 k겹 교차검증을 하면 데이터셋을 k번 나누어 k개의 모델을 만들어 학습시킨다.

 

단순 k겹 교차검증

 

k=5로 설정해서 k fold cross validation을 하면 이렇게 같은 비율을 유지하면서 모든 데이터를 train set과 test set으로 골고루 활용하면서 모델을 만들게 된다.



1번 모델은 1번 폴드를 test set으로, 2~5번 폴드를 train set으로 활용해서 모델을 훈련한다. 2번 모델은 2번 폴드를 test set으로, 나머지 폴드를 train set으로 활용한다. 나머지 모델들도 마찬가지 방법으로 모델을 훈련시킨다. 그러면 모델이 k번 돌아가게 되고, 결과도 k번 나오고 정확도도 k번 측정하게 된다. 그 k번의 평균값이 바로 모델의 성능이 된다.

 



사이킷런에서는 단순 교차검증인 cross_val_score 함수와 계층적 교차검증인 StratifiedKFold, KFold 함수를 제공한다. 데이터가 편향되어 있다면 cross_val_score로 성능 평가가 어렵기 때문에 stratified k-fold cross-validation을 쓰게 된다.


보통 회귀 모델에서는 단순 kfold를, 분류모델에서는 계층적 kfold를 사용한다.

 

from sklearn.datasets import load_iris 
from sklearn.model_selection import cross_val_score, StratifiedKFold, train_test_split 
from sklearn.linear_model import LogisticRegression 
iris = load_iris() logreg = LogisticRegression() 

#단순 교차 검증
scores = cross_val_score(logreg, iris.data, iris.target, cv=3)

#각 모델의 정확도 print(scores) 

#교차 검증의 정확도 (평균값) print(scores.mean()) 

>>[0.98 0.96 0.98] >>0.9733333333333333

 

계층별 k겹 교차 검증

계층적 k겹 교차검증은 폴드 안의 클래스 비율이 전체 데이터셋의 클래스 비율과 같도록 데이터를 나눈다는 점에서 단순 k겹 교차검증과 차이가 있다. 분류 모델에서는 앞서 말한 것과 같이 StratifiedKFold를 사용해서 훈련세트와 테스트세트를 나눈다.

from sklearn.model_selection import StratifiedKFold 

skfolds = StratifiedKFold(n_splits=3, random_state=42, shuffle=True)

각 파라미터에 대해 알아보자.

 

1. n_splits

n_splits은 k겹 교차검증을 몇 번 수행할 것인가를 지정하는 것으로 기본값은 5이다. 주로 5 또는 10으로 많이 설정하지만 사용하는 데이터의 특성에 따라 n_splits 값은 달라질 것이다.



2. shuffle

shuffle의 디폴트값은 False이다. True로 설정을 하면 fold를 나누기 전에 데이터셋을 무작위로 섞게 된다.



3. random_state

random_state를 설정하면 작업을 여러번 해도 폴드가 바뀌지 않아 결과값을 유지할 수 있다. 반드시 필요한 것은 아니지만 똑같은 작업을 여러번 하는 경우가 많기 때문에 보통은 아무 숫자로나 설정한다.

 

 

 

주의할 점은 cross_val_score 함수를 사용하면 KFold의 매개변수를 제어할 수 있는 방법이 없기 때문에 분류 모델에서 cross_val_score 함수를 사용한다면 KFold 객체를 만들어 cv 매개변수로 전달해야 한다.

 

from sklearn.model_selection import StratifiedKFold, KFold 
from sklearn.model_selection import cross_val_score 

#StratifiedKFold 
skfold = StratifiedKFold(n_splits=3, shuffle = True, random_state=42) 
scores = cross_val_score(logreg, iris.data, iris.target, cv=kfold) print(scores) 
>>>array([1. , 0.94, 0.96])

#KFold
kfold = KFold(n_splits=3, shuffle = True, random_state=42) 
scores2 = cross_val_score(logreg, iris.data, iris.target, cv=kfold) 
scores2 
>>>array([1. , 0.92, 0.98])

 

 

교차 검증의 장점

1. test set에 모든 데이터가 최소 한번씩 들어가기 때문에 모델이 더 잘 일반화 됨

2. 분할을 한 번 했을 때보다 데이터를 더 효과적으로 사용해 더 정확한 모델을 만들 수 있음



교차 검증의 단점

1. 연산 비용이 늘어남 (k개의 모델을 만들어야 하므로 데이터를 한 번 나눴을 때에 비해 느림)