수달이네 기술 블로그

18. K-Fold 교차검증 본문

AI공부/머신러닝

18. K-Fold 교차검증

슬픈 수달이 2026. 1. 12. 16:08

교차 검증(Cross Validation)

모델의 성능을 더 정확히 평가하기 위해 데이터를 반복적으로 학습용 데이터와 검증용 데이터로 나누어 사용하는 방식

  • 여러가지 방법으로 결과를 섞어서 평균을 내는 방법
  • 데이터 분할에 따른 편향을 줄이고, 일반화 성능을 신뢰성있게 측정한다.
    • 위같은 이유로 데이터셋이 작거나 편향되었을때 유용함. + 과적합 방지
  • ex)K-Fold 교차 검증: 데이터를 k개의 동일한 크기로 나누고, 각 부분을 한번씩 검증 데이터로 사용해 모델을 평가

fold를 여러개로 나누어 한부분을 test나머지 부분을 train하는데 쓴다.

  • 이걸 폴드마다 반복하고, 해당 파라미터의 평균을 사용한다.
from sklearn.model_selection import KFold

kf = KFold(n_splits = 5)
kf

# KFold(n_splits=5, random_state=None, shuffle=False)
  • n_splits = 5: 5개의 fold로 나누어 준다.
  • random_state = None : 랜덤 seed값이 없음 즉, 데이터를 섞지 않는다.
  • shuffle = False: 섞지 않는다.
for train_index, test_index in kf.split(range(len(hotel_df))):
    print("TRAIN:", train_index, "TEST:", test_index)

# TRAIN: [ 23842  23843  23844 ... 119207 119208 119209] TEST: [    0     1     2 ... 23839 23840 23841]
# TRAIN: [     0      1      2 ... 119207 119208 119209] TEST: [23842 23843 23844 ... 47681 47682 47683]
# TRAIN: [     0      1      2 ... 119207 119208 119209] TEST: [47684 47685 47686 ... 71523 71524 71525]
# TRAIN: [     0      1      2 ... 119207 119208 119209] TEST: [71526 71527 71528 ... 95365 95366 95367]
# TRAIN: [    0     1     2 ... 95365 95366 95367] TEST: [ 95368  95369  95370 ... 119207 119208 119209]

  • 위 결과물으로 나눠진 값을 보면, test값이 fold별로 23842개씩 나눠진 것을 알 수 있다.
    • test fold를 보면 명확하게 보임
  • 그러나 섞이지 않았기 때문에 편향적일 수 있다. 데이터를 섞어보자.
kf = KFold(n_splits = 5, shuffle=True, random_state=42)
for train_index, test_index in kf.split(range(len(hotel_df))):
    print("TRAIN:", train_index, "TEST:", test_index)

# TRAIN: [     1      2      4 ... 119206 119207 119208] TEST: [     0      3     23 ... 119191 119196 119209]
# TRAIN: [     0      1      2 ... 119205 119208 119209] TEST: [     8     12     17 ... 119204 119206 119207]
# TRAIN: [     0      2      3 ... 119207 119208 119209] TEST: [     1      4      6 ... 119180 119183 119193]
# TRAIN: [     0      1      2 ... 119206 119207 119209] TEST: [     9     10     14 ... 119200 119202 119208]
# TRAIN: [     0      1      3 ... 119207 119208 119209] TEST: [     2      5     15 ... 119197 119203 119205]
  • 이번 결과값을 보면 잘 섞인 것을 알 수 있는게, 아까처럼 test가 시작하는 위치가 뒤죽박죽이다.

적용

acc_list = []

for train_index, test_index in kf.split(range(len(hotel_df))):
    X= hotel_df.drop('is_canceled', axis=1)
    y = hotel_df['is_canceled']

    X_train = X.iloc[train_index]   # 훈련 데이터
    X_test = X.iloc[test_index]     # 테스트 데이터
    y_train = y.iloc[train_index]   # 훈련 데이터의 타겟 값
    y_test = y.iloc[test_index]     # 테스트 데이터의 타겟 값

    rf = RandomForestClassifier(random_state=42)
    rf.fit(X_train, y_train)
    pred_rf = rf.predict(X_test)
    
    acc_list.append(accuracy_score(y_test, pred_rf))# 각 폴드별 정확도 저장
  • X에 독립변수, y에 종속변수를 넣어주고,
  • 각 train, test변수에 각 종속변수 독립변수에 맞는 인덱스로 iloc로 값을 넣어 데이터를 나눠준다.
  • 이후 나눈 데이터를 학습해주고, 해당 정확도를 acc_list에 저장한다.
acc_list
# [1.0, 1.0, 1.0, 1.0, 1.0]
  • 어차피 현재 1.0의 정확도를 보였기에 의미는 없지만, 평균을 내보면
np.array(acc_list).mean()
# np.float64(1.0)
  • 위와 같이 표시된다.