ML

머신러닝 2_4 교차검증

haribodang 2022. 4. 28. 14:13
반응형

1. 교차 검증

  • 교차검증을 하는 이유 - 과적합에 따른 성능저하 개선
    • 과적합 이란? 모델이 학습데이터에만 과도하게 최적화 되어 실제 예측을 다른 데이터로 수행할경우 예측성능이 과도하게 떨어지는것, 고정된 학습/테스트 데이터로 평가를 하다보면 테스트 데이터에만 최적을 성능을 발휘하도록 평향된 모델을 유도 하는 경우가 생기고 결국 테스트 데이터에만 과적합 되는 학습 모델이 만들어져 다른 테스트 데이터가 들어오는 경우 성능이 저하
  • 학습데이터를 다시 분할하여 학습 데이터와 학습된 모델의 성능을 일차 평가하는 검증 데이터로 나눔.
  • 검증데이터를 바꿔가며 미리 테스트를 해봄.
  • 머신러닝은 데이터의 의존이 심하기 때문에 여러번 검증 데이터셋으로 학습과 평가를 수행하여 그결과에 따라 하이퍼 파라미터 튜닝등의 모델 최적화를 쉽게할수있다.
  • 대부분 ML 모델의 성능은 교차 검증 기반으로 1차 평가후 최종적으로 테스트 데이터 세트에 적용해 평가하는 프로세스 - 학습 데이터를 다시 분할하여 학습 데이터와 학습된 모델의 성능을 일차 평가하는 검증 데이터로 나눔
  • K 폴드 -가장보편적으로 사용 되는교차 검증 기법 , K 개의 데이터 폴드 세트를 만들어 K 번만큼 각 폴드 세트 에 학습과 검증평가를 반복 적으로 수행하여 K개의 평가를 평균한 결과를 가지고 예측성능을 평가 하는 방법

교차검증

 

2. KFold 와 StratifiedKFold

#사이킷 런에서 K 폴드 교차 검증 프로세스를 구현하기위해 KFold 와 StratifiedKFold 클래스를 제공
# 5개의 폴드 세트로 분리하는 KFold 객체와 폴드 세트별 정확도를 담을 리스트 객체 생성.

 

from sklearn.model_selection import KFold
kfold = KFold(n_splits=5)
cv_accuracy = []
print('붓꽃 데이터 세트 크기:',features.shape[0])


n_iter = 0
#전체 붓꽃 데이터 세트 크기가 150 인데 학습용 데이터 세트는 4/5 - 120개, 검증 데이터 세트는 1/5 30개 로 분할됨.
# KFold객체의 split( ) 호출하면 폴드 별 학습용, 검증용 테스트의 로우 인덱스를 array로 반환
for train_index, test_index in kfold.split(features):
# kfold.split( )으로 반환된 인덱스를 이용하여 학습용, 검증용 테스트 데이터 추출
X_train, X_test = features[train_index], features[test_index]
y_train, y_test = label[train_index], label[test_index]

# 개별 iteration별 정확도를 합하여 평균 정확도 계산
print('\n## 평균 검증 정확도:', np.mean(cv_accuracy))

* Stratified K 폴드 - 불균형한 분포도(특정레이블값이 특이하게 많거나 매우적어서 값의 분포가 한쪽으로 치우치는 것을 의미 )를 가진 레이블 데이터를 집합을 위한 K 폴드 방식
- 학습 데이터와 검증데이터 세트가 가지는 레이블 분포도가 유사하도록 검증 데이터 추출 해야한다.




전체 레이블 값의 분포도를 반영 하지 못하는 문제를 해결해주는 것이 Stratified KFold

from sklearn.model_selection import StratifiedKFold

skf = StratifiedKFold(n_splits=3)
n_iter=0

for train_index, test_index in skf.split(iris_df, iris_df['label']): # kfold 와 달리 split 메서드 인자로 피쳐 데이터 세트와 레이블 데이터세트를 반드시 넣어줘야함.
n_iter += 1
label_train= iris_df['label'].iloc[train_index]
label_test= iris_df['label'].iloc[test_index]
print('## 교차 검증: {0}'.format(n_iter))
print('학습 레이블 데이터 분포:\n', label_train.value_counts())
print('검증 레이블 데이터 분포:\n', label_test.value_counts())#학습레이블과 검증 레이블 데이터 값의 분포도가 동일하게 할당됨.



회귀: StratifiedKFold 지원하지않음. 회귀의 결정값은 이산값 형태의 레이블이아니고 연속된 숫자값이기 때문에 결정값 별로 분포를 정하는 의미가 없다.

분류 : StratifiedKFold 로 분할되어야함

 

3. cross_val_score


* cross_val_score( ) - 교차검증을 보다 간편하게

- KFold 클래스를 이용한 교차 검증방법
- 폴드 세트설정
- For 루프에서 반복적으로 학습/ 검증 데이터 추출및 학습과 예측을 수행
- 폴드 세트별로 예측 성능을 평균하여 최종성능 평가

—> cross_val_score() 함수로 폴드 세트 추출, 학습/예측 , 평가를 한번에 수행

- estimator - 알고리즘 클래스(classifier, regressor)
- X - 피처 데이터세트
- y - 레이블데이터세트
- scoring - 예측성능평가지표
- cv- 교차검증 폴드수
- 반환값 -cv 로 지정된 횟수만큼 scoring 파라미터로 지정된 성능지표로 결과값을 배열형태로 반환
- 분류(classifier) 가입력되면 stratifiedK폴드방식으로 레이블값 분포에따라 학습/ 테스트 세트 분할
- 회기(regressor) 가 입력되면 Kfold 방식으로 분할

from sklearn.model_selection import cross_val_score , cross_validate # cross_validate : cross_val_score는 단하나의 평가 지표만 가능하지만 여러개의 평가지표를 반환해준다.


# 성능 지표는 정확도(accuracy) , 교차 검증 세트는 3개
scores = cross_val_score(dt_clf , data , label , scoring='accuracy',cv=3)
print('교차 검증별 정확도:',np.round(scores, 4))
print('평균 검증 정확도:', np.round(np.mean(scores), 4)) # 평가 결과값을 평균하여 평가수치로 사용 # StratifiedKFold 의 수행결과와 동일하다., 내부적으로 StratifiedKFold를 이용하기 때문

 

4. GridSearchCV


* GridSearchCV-- 교차 검증과 최적 하이퍼 파라미터 튜닝을 한번에
- 사이킷런은 GridSearchCV를 이용해 회귀나 분류 같은 알고리즘에 사용되는 하이퍼 파라미터를 순차적으로 입력하면서 편리하게 최적의 파라미터를 도출 할수 있는 방안을 제공 한다.
- 파라미터순차적용 횟수 * cv세트수 = 학습/검증 총수행횟수
- estimator - classifier, regressor, pipeline
- param_grid - key + 리스트 값을 가지는 딕셔너리 / estimator 의 튜닝을 위해 파라미터 명과 사용될 여러 파라미터 값 지정
- scoring - 예측성능평가지표(예 - 정확도 의경우 ‘accuracy’ 문자열)
- cv - 교차검증을 위해 분할되는 학습/테스트 세트의 개수
- refit - 디폴트 true / 가장최적의 하이퍼 파라미터 찾은 뒤 입력된 estimator 객체를 해당 하이퍼 파라미터로 재학습


from sklearn.model_selection import GridSearchCV, train_test_split


# 데이터를 로딩하고 학습데이타와 테스트 데이터 분리


### parameter 들을 dictionary 형태로 설정 { 'parameter_Name' : [ ] }

parameters = {'max_depth':[1, 2, 3], 'min_samples_split':[2,3]} #결정트리 모델에서의 최대 트리 깊이 (max_depth) , 노드를 분할하기 위한 최소한의 샘플데이터 개수 (min_sample_split)

import pandas as pd

# param_grid의 하이퍼 파라미터들을 3개의 train, test set fold 로 나누어서 테스트 수행 설정.
### refit=True 가 default 임. True이면 가장 좋은 파라미터 설정으로 재 학습 시킴.
grid_dtree = GridSearchCV(dtree, param_grid=parameters, cv=3, refit=True, return_train_score=True)

# 붓꽃 Train 데이터로 param_grid의 하이퍼 파라미터들을 순차적으로 학습/평가 .
grid_dtree.fit(X_train, y_train)

# GridSearchCV 결과는 cv_results_ 라는 딕셔너리로 저장됨. 이를 DataFrame으로 변환
scores_df = pd.DataFrame(grid_dtree.cv_results_)
scores_df[['params', 'mean_test_score', 'rank_test_score',
'split0_test_score', 'split1_test_score', 'split2_test_score']]


#params: 수행할때마다 적용된 개별 하이퍼 파라미터 값
#rank_test_score : 하이퍼 파라미터 별로 성능이 좋은 score 순위, 1 이 가장 뛰어난 순위 (최적의 하이퍼 파라미터)
#mean_test_score : 개별하이퍼 파라미터 별로 cv 의 폴딩 테스트 세트에 대해 총수행한 평가 평균값

grid_dtree.cv_results_

print('GridSearchCV 최적 파라미터:', grid_dtree.best_params_)
print('GridSearchCV 최고 정확도: {0:.4f}'.format(grid_dtree.best_score_))

# refit=True로 설정된 GridSearchCV 객체가 fit()을 수행 시 학습이 완료된 Estimator를 내포하고 있으므로 predict()를 통해 예측도 가능.
pred = grid_dtree.predict(X_test)
print('테스트 데이터 세트 정확도: {0:.4f}'.format(accuracy_score(y_test,pred)))

# GridSearchCV의 refit으로 이미 학습이 된 estimator 반환
estimator = grid_dtree.best_estimator_

# GridSearchCV의 best_estimator_는 이미 최적 하이퍼 파라미터로 학습이 됨
pred = estimator.predict(X_test)
print('테스트 데이터 세트 정확도: {0:.4f}'.format(accuracy_score(y_test,pred)))

# 학습데이터를 GridSearchCV를 이용해 최적 하이퍼 파라미터 튜닝을 수행한뒤에 별도의 테스트 세트에서 평가 !

반응형