세조목

머신러닝 심화 복습(교차검증(K-Fold, StratifiedKFold))(24.05.10) 본문

데이터 분석 공부/머신러닝

머신러닝 심화 복습(교차검증(K-Fold, StratifiedKFold))(24.05.10)

세조목 2024. 5. 10. 12:04

머신러닝을 할 때 하나의 데이터셋을 train, test 데이터셋으로 나누는데

7:3 내지 8:2로 나누는 것이 일반적이다.

train 데이터셋으로 학습을 시키고 이 모델을 test 데이터셋에 적용시켜보는 것이다.

그런데 만약 train 데이터셋에 포함된 데이터의 개수가 충분하지 않다면 과적합이 발생하지 않을까?

 

이 때 필요한 것이 '교차 검증(Cross Validation)'이다.

교차 검증이란 train 데이터셋에 포함된 데이터셋을 n개로 split해서

모델을 학습시키고 모델을 최적화시키는 작업이다.

위 이미지에서의 경우 train dataset을 5개로 split 한 후 각각의 Fold를

학습용, 검증용으로 지정해서 모델을 학습시켜본다.

Fold1, 2, 3, 4, 5를 순서대로 검증용으로 지정하는 것이다.

학습 데이터와 검증 데이터 index를 나타낸건데

위 예시에서는 [0, 8, 13, ..., 876, 886, 887] index가 포함된 Fold가 검증용으로 지정된 경우다.

from sklearn.model_selection import KFold
import numpy as np

kfold = KFold(n_splits = 5, shuffle=True)
n_iter = 0
scores = []
X = train_df_2[['Age_mm_sc', 'Family_mm_sc', 'Fare_sd_sc', 'Pclass_le', 'Sex_le', 'Embarked_C', 'Embarked_Q', 'Embarked_S']]
y = train_df_2['Survived']
for i, (train_index, test_index) in enumerate(kfold.split(X)):
  X_train, X_test = X.values[train_index], X.values[test_index]
  y_train, y_test = y.values[train_index], y.values[test_index]

  from sklearn.linear_model import LogisticRegression
  from sklearn.metrics import accuracy_score
  model_lor2 = LogisticRegression()
  model_lor2.fit(X_train, y_train)
  y_pred2 = model_lor2.predict(X_test)
  accuracy = accuracy_score(y_test, y_pred2).round(3)
  print(f'{i}번째 교차검증 정확도 : {accuracy}')
  scores.append(accuracy)

print(f'평균 정확도 : {np.mean(scores)}')

이 코드는 KFold 교차검증 방식을 적용하는 코드인데

중간 부분을 보면 아래와 같은 코드가 있다.

X_train, X_test = X.values[train_index], X.values[test_index]
y_train, y_test = y.values[train_index], y.values[test_index]

 

for문으로 train_index와 test_index를 나누었으니

독립변수와 종속변수를 각각 train, test 데이터셋으로 나눠주는 것이다.

그래야 model을 학습시킬 수 있기 때문이다.

 

그런데 kfold=KFold(n_splits = 5, shuffle=True) 코드에서 shuffle이라는 파라미터가 있다.

이건 말 그대로 무작위로 섞는다는 말인데

무작위로 섞지 않을 경우 위에서부터 아래로 순서대로 split된다.

이게 왜 문제가 되냐하면

예를 들어 음성일 확률에 해당하는 레이블 0, 양성일 확률에 해당하는 레이블 1이 있을 때

1의 비중이 0.001%로 아주 적을 수 있는데

shuffle하지 않고 split할 경우 각 Fold가 0과 1의 비율을 제대로 반영할 수 없게된다.

그래서 shuffle 파라미터를 사용하는데 이 방법 외에도 StratifiedKFold 모델을 사용하면 불균형 문제를 해결할 수 있다.

from sklearn.model_selection import StratifiedKFold
S_kfold = StratifiedKFold(n_splits=5)
score=[]
X = train_df_2[['Age_mm_sc', 'Family_mm_sc', 'Fare_sd_sc', 'Pclass_le', 'Sex_le', 'Embarked_C', 'Embarked_Q', 'Embarked_S']]
y = train_df_2['Survived']
for i, (train_index, test_index) in enumerate(S_kfold.split(X, y)):
  X_train, X_test = X.values[train_index], X.values[test_index]
  y_train, y_test = y.values[train_index], y.values[test_index]

  from sklearn.linear_model import LogisticRegression
  from sklearn.metrics import accuracy_score
  model_lor2 = LogisticRegression()
  model_lor2.fit(X_train, y_train)
  y_pred2 = model_lor2.predict(X_test)
  accuracy = accuracy_score(y_test, y_pred2).round(3)
  print(f'{i}번째 교차검증 정확도 : {accuracy}')
  scores.append(accuracy)

print(f'평균 정확도 : {np.mean(scores)}')

KFold 모델과 코드는 거의 대부분 동일한데

S_kfold.split( )의 소괄호에 독립변수 뿐만 아니라 종속변수도 함께 넣어준다는 부분이 다르다.

그래서 보통 LogisticRregression과 같은 분류 모델링을 할 때,

그리고 앞서 언급한 예시에서와 같이 레이블 데이터의 왜곡이 있을 때

StratifiedKFold 모델을 사용한다.