AI

교차 검증(Cross validation)

Lagom92 2020. 8. 21. 22:40

 

 

만약 모델을 학습시키기 위해 데이터를 train set와 test set로 나눈 후 파라미터를 수정하면서 계속 학습을 한다면 train set가 고정된 상태에서 계속 반복되면서 모델이 과적합(overfitting) 될 수 있다.

이를 해결하고자 하는 것이 바로 교차 검증(cross validation)이다.

 

 

교차 검증

  • 일반화 성능 향상을 위해 훈련 세트와 테스트 세트로 한 번 나누는 것보다 더 안정적이고 뛰어난 평가 방법

  • 데이터 편중을 막기 위함

  • 별도의 여러 세트로 구성된 학습 데이터 세트와 검증 데이터 세트에서 학습과 평가를 수행

  • 연산 비용이 늘어나는 단점이 있음 (k배 더 느림)

 

 

from sklearn.model_selection import cross_val_score

 

  • Parameter and Return
cross_val_score(estimator, X, y=None, *, groups=None, scoring=None, cv=None, n_jobs=None, verbose=0, fit_params=None, pre_dispatch='2*n_jobs', error_score=nan)


'''
Parameter

- estimator : 평가하려는 모델
- X : 훈련 데이터
- y : 타깃 레이블
- cv : 교차 검증 분할 수(k)

Return

- 교차 검증 결과 정확도 점수의 배열
'''

 

 

Iris 데이터로 사용해보기

 

from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier

# iris 데이터 불러오기
iris = load_iris()

# model
model_lr = LogisticRegression()
model_dt = DecisionTreeClassifier(random_state=42)

scores = cross_val_score(model_lr, iris.data, iris.target)
print("교차 검증 점수: ", scores)

scores = cross_val_score(model_dt, iris.data, iris.target)
print("교차 검증 점수: ", scores)
교차 검증 점수:  [0.96666667 1.         0.93333333 0.96666667 1.        ]
교차 검증 점수:  [0.96666667 0.96666667 0.9        0.93333333 1.        ]

 

# 폴드의 수 조절하기(cv)
scores = cross_val_score(model_dt, iris.data, iris.target, cv=3)
print("교차 검증 점수: ", scores)
교차 검증 점수:  [0.98 0.94 0.96]

 

# 보통 교차 검증의 정확도를 간단하게 나타내기 위해 평균을 사용한다.
print("교차 검증 점수: ", scores.mean())
교차 검증 점수:  0.96

 

 

그런데

  • 데이터셋을 나열 순서대로 k개의 폴드를 나누는 것은 항상 좋지는 않다.

 

iris = load_iris()

print("Iris 레이블:\n{}".format(iris.target))
Iris 레이블:
  [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
   0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
   1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
   2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
   2 2]

 

  • 결과에서 볼 수 있듯이 1/3은 클래스 0, 1/3은 클래스 1, 1/3은 클래스 2이다.
  • 이 데이터에 3-겹 교차 검증을 적용한다면 첫 번째 폴드는 클래스 0만 가지고 있으므로 정확도는 0이 된다.
  • 두 번째, 세 번째도 같은 방법으로 정확도는 0이 된다.

 

K-fold

from sklearn.model_selection import KFold

kfold = KFold(n_splits=3)
scores = cross_val_score(model_dt, iris.data, iris.target, cv=kfold)
print("교차 검증 점수: ", scores)
교차 검증 점수:  [0. 0. 0.]

 

  • 해결 방법으로는 shuffle=True 를 사용하거나 StratifiedKFold 를 사용하면 된다.

 

# 데이터를 분할하기 전에 섞어주면 결과가 향상된다.
kfold = KFold(n_splits=3, shuffle=True, random_state=0)
scores = cross_val_score(model_dt, iris.data, iris.target, cv=kfold)
print("교차 검증 점수: ", scores)
교차 검증 점수:  [0.96 0.96 0.96]

 

계층별 k-fold 교차 검증

from sklearn.model_selection import StratifiedKFold

kfold = StratifiedKFold(n_splits=3)
scores = cross_val_score(model_dt, iris.data, iris.target, cv=kfold)
print("교차 검증 점수: ", scores)
교차 검증 점수:  [0.98 0.94 0.96]

 

  • StratifiedKFold는 데이터가 편향되어 있는 경우에 주로 사용된다.

 

 

참고로

  • 회귀에서는 k-fold 교차 검증을 사용하고,
  • 분류에서는 계층별 k-fold 교차 검증을 주로 사용한다.

 

또한

 

  • cross_val_score 함수에는 KFold의 매개변수를 제어할 수가 없으므로, 따로 KFold 객체를 만들고 매개변수를 조정한 다음에 cross_val_score의 cv 매개변수에 넣어야 한다.



 

이외에도 다양한 교차 검증 방법들이 있다.

 

임의 분할 교차 검증 (shuffle-split cross-validation)

  • 반복 횟수를 훈련 세트나 테스트 세트의 크기와 독립적으로 조절해야 할 때 유용
from sklearn.model_selection import ShuffleSplit

 

그룹별 교차 검증 (groups cross-validation)

  • 데이터 안에 매우 연관된 그룹이 있을 때
from sklearn.model_selection import GroupKFold

 

반복 교차 검증

데이터셋의 크기가 크지 않을 경우 안정된 검증 점수를 얻기 위해 교차 검증을 반복하여 여러 번 수행

  • RepeatedKFold : 회귀에 사용
  • RepeatedStratifiedKFold : 분류에 사용
from sklearn.model_selection import RepeatedStratifiedKFold

 

등등...




 

 


Reference

 

 

 

 

 

댓글수0