그래도해야지어떡해

검증(Validation)/ 교차검증(cross validation/K-fold cross validation) 본문

ML

검증(Validation)/ 교차검증(cross validation/K-fold cross validation)

jerrry 2022. 2. 21. 12:42

트레이닝을 하는 과정에서 테스트 셋으로 모델학습이 잘 되었나 확인하는 과정을 계속 반복하다 보면 결국, 테스트셋에 적합하게 학습된 모델이 만들어지게 된다.

 

이를 방지하기 위해 모델이 학습되는 과정에서 잘 학습이 되고 있는지 확인하는 용도로 사용할 데이터 셋이 필요하다.

-> 트레이닝 셋의 일부(보통 20-30%)를 검증 셋으로 설정

 

1. 트레이닝 셋으로 모델 학습

2. validation set으로 1에서 학습한 모델 평가

3. 2의 결과를 바탕으로 parameter 조정

4. 1~3의 과정을 반복하면서 가장 좋은 성능을 내는 모델 선택

5. 4에서 선택된 모델의 parameter를 사용하여 전체 training set(training set + validation set)에서 모델을 다시 훈련

6. test set에서 최종 성능 평가 

 

 

교차검증(cross validation)

validation set을 만들면서 training set이 줄어들었다. 하지만, 보통 많은 데이터를 훈련에 사용할수록 좋은 모델이 만들어진다. 

그렇다고 validation set을 너무 적은 양으로 사용하면 validation score가 들쭉날쭉 불안정 할것이다. 

 

이럴 때 해결방법이 바로 교차검증이다!

 

cross validation은 validation set을 떼어내어 평가하는 과정을 여러번 반복한다. 이 때 매번 다른 곳에서 떼어낸다. 이후 이 점수들의 평균을 구해서 최종적인 validation 점수를 구한다.

 

ex) 3-fold cross validation

위의 그림에서, 각 행 내의 training 블럭 2개는 모델 훈련에 사용되고, validation 블럭은 모델평가에 사용된다.

이와 같은 과정을 validation 블럭을 섞어가며 겹치지 않게 3번 반복하여 검증하는 것을 3-fold cross validation라고 한다.

 

일반적으로 통칭하여  k-fold cross validation이라고 하며, training set을 몇개의 파트(블럭)로 나누냐에 따라 다르게 부른다.

 

보통 5 or 10-fold cross validation을 많이 사용하는데, 이렇게 하면 데이터의 80~90%까지 훈련에 사용할 수 있다.

사이킷런에는 cross_validate()라는 함수를 사용할 수 있다. 이 함수는 기본적으로 5-fold cross validation을 수행한다.

from sklearn.model_selection import cross_validate
scores = cross_validate(dt, train_input, train_target)
# fit_time(:모델을 훈련하는 시간), score_time(:검증하는 시간), test_score를 가진 딕셔너리를 반환
print(scores)

test_score에 담긴 값들의 평균을 구하면, cross validation의 최종 점수를 구할 수 있다.

fit_time과 score_time을 제외한 test_score만 출력하고 싶을 때는 cross_val_score() 함수를 사용하면 된다.

 

fold를 나누기 위해서 사이킷런의 분할기를 사용한다.

이 때, 분류인지 회귀인지에 따라 다른 분할기가 사용된다.

* 분류 - 타깃 클래스(정답 클래스)를 골고루 나눠야 하므로 StratifiedKFold를 사용

* 회귀 - KFold 분할기를 사용

from sklearn.model_selection import StratifiedKFold
splitter = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_validate(dt, train_input, train_target, cv=splitter)
print(np.mean(scores['test_score']))
Comments