이것저것 공부 기록하기

[MachineLearning] Stratified K-Fold 본문

MachineLearning

[MachineLearning] Stratified K-Fold

얍욥얍 2021. 10. 20. 22:38

교차검증이란?

 

머신러닝을 돌리기 전에 train test로 나눠 머신을 훈련한다. 하지만 이 훈련 때 학습 데이터에 과도하게 초점을 맞춰 머신이 훈련될 수가 있다.

 

이 같은 경우에는 훈련시에는 점수가 잘 나오지만 실제 테스트를 할 때는 점수가 잘 나오지 않는다.

 

이걸 과적합(overfitting)이라고 한다. 

 

우리는 훈련시에 이 같은 과적합을 막아야 한다. 이걸 위해 교차검증 이란 것 을 사용한다. 

 

교차검증이란 훈련 데이터 세트를 바꿔가면 훈련하면서 나온 평균을 정확도로 보는 방법을 뜻한다.

 

이렇게 훈련 데이터 세트를 교차하면서 검증을 하기에 교차 검증이라고 한다.

 

 

 

 


# K-fold 교차검증

 

 

학습세트와 검증 세트를 나눠 반복해서 검증한다. 이걸 k값만큼의 폴드 세트에 k번의 학습과 검증을 한다. 이러한 방법으로 k번 평가를 하게 된다.

 

한 번의 학습을 통해 평가를 할 경우 과적합이 일어날 가능성이 크다. 이럴 때를 대비해 교차검증을 통해 과적합을 막아준다.

 

 

# K-Fold 사용법

 

from sklearn.datasets import load_iris
from sklearn.tree     import DecisionTreeClassifier
from sklearn.model_selection import train_test_split

from sklearn.model_selection import KFold

import pandas as pd
import numpy  as np

sklearn을 통해 KFold를 import 해준다.

 

 

fold_iris.keys()

간단하게 sklearn을 통해 데이터 셋을 가져오고

 

 

fold_iris = load_iris()
features = fold_iris.data
# print(features)
label    = fold_iris.target
# print(label)
fold_df_clf = DecisionTreeClassifier()

 그 부분에서 data(독립변수)와 target(종속변수) 를 가져온다.

 

그리고 여기서는 DecisionTree를 사용한다.

 

 

# 5개의 폴드 세트를 분리하여 각 폴드 세트별 정확도를 담을 리스트를 생성
kfold = KFold(n_splits=5)
cv_accuracy = []

우리는 KFold를 5개로 split할 예정이다. 이 값은 사용자가 임의로 정할 수 있다.

 

 

n_iter = 0 
for train_idx , test_idx in kfold.split(features) :
    X_train , X_test = features[train_idx] , features[test_idx]

    y_train , y_test = label[train_idx] , label[test_idx]

    # 학습을 진행하겠다면?
    fold_df_clf.fit(X_train , y_train)
    # 예측
    fold_pred = fold_df_clf.predict(X_test)
    
    # 정확도 측정
    n_iter += 1
    accuracy = np.round( accuracy_score(y_test , fold_pred) , 4) 
    print('\n{} 교차검증 정확도 : {} , 학습 데이터 크기 : {} , 검증 데이터 크기 : {}'.format(n_iter, accuracy, X_train.shape[0] , X_test.shape[0]))
    
    cv_accuracy.append(accuracy)
print('\n')

print('\n 평균검증 정확도 :  ' , np.mean(cv_accuracy)) 

위에서 분할했던 kfold를 넣고 split을 하는데 우리가 가지고 있던 fold_iris.data를 분할한다. 이것을 train_idx와 test_idx로 분할한다. 

 

이것을 통해 훈련하는 부분과 검증하는 부분을 나눈다. 그렇게 인덱스를 나누고 해당 하는 인덱스를 features와 label에 넣는다. 

 

지금 까지 했던 것을 토대로 예측을 한다. 이 예측은 for문에 의해서 5번 돌게끔 된다. 

 

 

 


 

# kfold 의 문제점

kfold의 경우 일정한 간격으로 잘라서 사용한다. 

 

여기서보면 답이 0 , 1, 2 이 세가지로 나눠지는데 만약에 이상황에서 잘라서 학습을하는데

 

0,1만 답으로 가지고 있는 학습데이터를 가지고 학습을 했을때는 2라는 답을 도출 할 수 없다.

 

0,2, 만 가지고 학습을 했을 경우에 1이라는 답을 도출 할 수 없다. 이것이 Kfold의 문제점이다.

 

 

 

 

 

 

이러한 문제를 해결하기 위해 나온것이  stratifiedkFold이다.

 

 


 

# stratifiedkFold

 

stratifiedkFold 는 target에 속성값의 개수를 동일하게 하게 가져감으로써 kfold 같이 데이터가 한곳으로 몰리는것을 방지한다.

 

# 레이블 값의 분포를 반영해주지 못하는 문제를 해결하기위해서 stratifieldKFold 를 이용
from sklearn.model_selection import StratifiedKFold

skf_iris = StratifiedKFold(n_splits=3)
cnt_iter = 0 

for train_idx , test_idx in skf_iris.split(kfold_iris_data_df , kfold_iris_data_df['target']) :
    # print(train_idx , test_idx)
    cnt_iter += 1
    label_train = kfold_iris_data_df['target'].iloc[train_idx]
    label_test  = kfold_iris_data_df['target'].iloc[test_idx]
    # print('label_train\n' , label_train)
    print('교차 검증 : {}'.format(cnt_iter))
    print('학습 레이블 데이터 분포 : \n' , label_train.value_counts())
    print('검증 레이블 데이터 분포 : \n' , label_test.value_counts())
    

지금 하고있는건 분류에서만 가능하다.

 

 

예제)

 

# [실습] random_state = 100
# 붓꽃 데이터 세트에서 Stratified KFold 를 이용하여 교차검증(3, 5)을 진행하고 평균정확도를 확인
# Stratified KFold 는 분류 , 회귀 X
# 회귀는 연속된 숫자 값이기 때문에 지원하지 않는다.


from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import KFold

# 회귀에서는 지원하지 않는다.
from sklearn.model_selection import StratifiedKFold

import pandas as pd
import numpy  as np

result_iris = load_iris()
result_features = result_iris.data
result_label    = result_iris.target

# 학습기 생성
result_clf = DecisionTreeClassifier(random_state=100)

 

 

result_skfold = StratifiedKFold(n_splits=3)
idx_iter=0
cv_accuracy=[]

# StratifiedKFold의 split( ) 호출시 반드시 레이블 데이터 셋도 추가 입력 필요  
for train_index, test_index  in result_skfold.split(features, label):
    # split( )으로 반환된 인덱스를 이용하여 학습용, 검증용 테스트 데이터 추출
    X_train, X_test = features[train_index], features[test_index]
    y_train, y_test = label[train_index], label[test_index]
    
    #학습 및 예측 
    result_clf.fit(X_train , y_train)    
    pred = result_clf.predict(X_test)

    # 반복 시 마다 정확도 측정 
    idx_iter += 1
    accuracy = np.round(accuracy_score(y_test,pred), 4)
    train_size = X_train.shape[0]
    test_size = X_test.shape[0]
    
    print('\n#{0} 교차 검증 정확도 :{1}, 학습 데이터 크기: {2}, 검증 데이터 크기: {3}'
          .format(idx_iter, accuracy, train_size, test_size))
    print('#{0} 검증 세트 인덱스:{1}'.format(idx_iter,test_index))
    cv_accuracy.append(accuracy)

 

 

    
# 교차 검증별 정확도 및 평균 정확도 계산 
print('\n## 교차 검증별 정확도:', np.round(cv_accuracy, 4))
print('## 평균 검증 정확도:', np.mean(cv_accuracy)) 

 


References

https://continuous-development.tistory.com/166

반응형
Comments