K-폴드 교차검증: K는 어떻게 고르고 폴드마다 결과는 왜 달라지는가

K-폴드 교차검증의 동작 원리와 계층적 K-폴드·LOOCV·그룹 K-폴드 변형, K 값 선택 기준, 중첩 교차검증까지 실무 관점에서 정리한다.

2026-08-13 · 최초 발행 2025-05-23

단순 분할이 놓치는 것

머신러닝 모델 개발에서 데이터를 어떻게 활용하는지는 최종 성능에 결정적인 영향을 미친다. 훈련·테스트를 한 번만 나누는 것만으로는 모델의 일반화 능력을 정확히 평가하기 어렵다. 데이터 분할 방식에 따른 우연한 결과(lucky split)를 방지하고, 제한된 데이터셋에서도 최대한의 학습 효과와 신뢰성 있는 검증을 확보하며, 과적합(overfitting) 또는 과소적합(underfitting)을 조기에 감지하려면 반복적인 분할·평가가 필요하다.

K개 폴드로 나눠 K번 검증한다는 것

K-폴드 교차검증(K-Fold Cross-Validation)은 데이터셋을 K개의 동일한 크기의 부분집합(폴드)으로 분할한다. 각 반복에서 K-1개의 폴드는 훈련용으로, 나머지 1개 폴드는 검증용으로 사용하며, 총 K번의 학습 및 평가를 반복한 뒤 성능 지표의 평균값을 산출한다. 모든 데이터가 최소 한 번은 검증 데이터로 쓰이기 때문에 편향이 줄어든다. 일반적으로 K=5 또는 K=10을 많이 쓴다(경험적 최적값).

K=5일 때 실제로 벌어지는 일

전체 데이터셋5개 폴드로 분할1차 반복: 폴드 1 검증용,나머지 훈련용2차 반복: 폴드 2 검증용,나머지 훈련용3차 반복: 폴드 3 검증용,나머지 훈련용4차 반복: 폴드 4 검증용,나머지 훈련용5차 반복: 폴드 5 검증용,나머지 훈련용 반복에서 성능 지표 측정K개 성능 지표의 평균 분산계산최종 모델 성능 평가

각 반복(fold)마다 정확도, F1 점수, RMSE 등 성능 지표를 측정하고, 최종적으로 K개 지표의 평균값을 모델의 실제 성능 추정치로 삼는다. 성능 지표의 분산(variance)을 보면 모델 안정성도 함께 가늠할 수 있다.

Python으로 5개 폴드를 직접 나눠보면

from sklearn.model_selection import KFold
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
import numpy as np

# 데이터 및 모델 준비
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14], [15, 16], [17, 18], [19, 20]])
y = np.array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
model = LogisticRegression()

# 5-폴드 교차검증 설정
kf = KFold(n_splits=5, shuffle=True, random_state=42)

# 교차검증 수행
fold_accuracies = []
for fold, (train_idx, val_idx) in enumerate(kf.split(X)):
    X_train, X_val = X[train_idx], X[val_idx]
    y_train, y_val = y[train_idx], y[val_idx]

    # 모델 학습 및 예측
    model.fit(X_train, y_train)
    y_pred = model.predict(X_val)

    # 성능 측정
    fold_accuracy = accuracy_score(y_val, y_pred)
    fold_accuracies.append(fold_accuracy)
    print(f"Fold {fold+1} 정확도: {fold_accuracy:.4f}")

# 최종 성능 평가
print(f"평균 정확도: {np.mean(fold_accuracies):.4f}")
print(f"정확도 표준편차: {np.std(fold_accuracies):.4f}")

상황에 따라 달라지는 변형들

계층적 K-폴드 교차검증(Stratified K-Fold)

불균형 데이터셋에서 각 폴드가 원본 데이터의 클래스 비율을 유지하도록 설계된 방식이다. 분류 문제에서 특히 유용하며 더 신뢰성 있는 결과를 준다.

from sklearn.model_selection import StratifiedKFold

skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
for train_idx, val_idx in skf.split(X, y):
    # 각 폴드에서 클래스 비율이 유지됨

Leave-One-Out 교차검증(LOOCV)

K-폴드의 극단적 형태로, K=n(데이터 개수)인 경우다. 각 반복에서 단 하나의 샘플만 검증용으로 쓴다. 계산 비용이 매우 높지만 작은 데이터셋에서는 유용하며, 편향(bias)은 낮은 대신 분산(variance)이 높다.

그룹 K-폴드(Group K-Fold)

특정 그룹이 훈련과 검증 세트에 동시에 나타나지 않도록 보장하는 방식이다. 시계열 데이터나 동일 주체의 반복 측정 데이터에 유용하며, 데이터 유출(data leakage) 방지 효과가 있다.

K를 얼마로 잡아야 하는가

  • K가 작을 경우(K=3~5): 계산 비용이 줄고 각 폴드에 더 많은 검증 데이터가 포함되지만, 분산이 높을 수 있다. 대규모 데이터셋에 적합하다.
  • K가 클 경우(K=10~20): 계산 비용은 늘지만 더 정확한 성능 추정이 가능하고 편향이 줄어든다. 소규모 데이터셋에 적합하다.
  • 일반적 권장사항: K=10이 많은 상황에서 좋은 절충안이며, 데이터셋 크기와 계산 자원에 따라 조정한다. 분류 문제에서는 계층적 K-폴드를 함께 고려한다.

데이터 효율과 계산 비용 사이

K-폴드 교차검증은 모든 데이터를 학습과 검증에 활용해 데이터 효율성을 높이고, 모델 성능의 일반화 능력을 더 정확히 추정하며, 과적합 위험을 줄이고 조기에 발견할 수 있게 해준다. 하이퍼파라미터 튜닝에도 매우 효과적이고, 모델 안정성에 대한 통계적 인사이트도 준다.

그 대가로 계산 비용이 K배 증가한다(K번의 모델 훈련이 필요하다). 대규모 데이터셋에서는 시간이 많이 들고, 시간 의존적 데이터(시계열)에는 적합하지 않다. 내부 검증 세트에 대한 하이퍼파라미터 과적합 위험도 존재한다.

의료·금융·추천 시스템에서 K-폴드를 쓰는 방식

희귀 질환 진단에서

제한된 환자 데이터를 최대한 활용해야 하는 희귀 질환 진단 모델에서는 각 폴드별 성능 편차가 크면 모델 불안정성의 신호로 해석한다. 계층적 K-폴드로 질환 유무 비율을 유지하며 검증한다.

불균형 거래 데이터에서

금융 사기 탐지처럼 정상 거래가 사기 거래보다 훨씬 많은 불균형 데이터셋에는 계층적 K-폴드를 적용하고, 정밀도·재현율·F1 점수 등 다양한 성능 지표의 평균값을 측정한다. 모델 임계값(threshold) 설정에도 K-폴드 결과를 활용한다.

사용자-아이템 데이터에서

추천 시스템에서는 사용자-아이템 상호작용 데이터에 그룹 K-폴드를 적용해 동일 사용자 데이터가 훈련·검증 세트에 나뉘어 들어가지 않도록 구성하고, 콜드 스타트 문제 시뮬레이션에 활용한다.

하이퍼파라미터 튜닝과 함께 쓰는 중첩 교차검증

내포된 교차검증(Nested Cross-Validation)은 외부 K-폴드로 모델 성능을 평가하고, 내부 K-폴드로 하이퍼파라미터를 최적화하는 방식이다.

전체 데이터셋외부 K-폴드외부 폴드 1외부 폴드 2...훈련 데이터테스트 데이터내부 K-폴드하이퍼파라미터 튜닝최적 모델 선택테스트 데이터로 평가반복...

GridSearchCV 또는 RandomizedSearchCV를 KFold와 결합해 구현하며, 이런 이중 최적화를 통해 더 견고한 모델을 개발할 수 있다.

폴드별 점수를 어떻게 해석할까

  • 평균 성능: 모델의 전반적 성능 추정치
  • 표준편차: 모델 안정성 지표, 낮을수록 안정적
  • 최소/최대 성능: 최악·최선의 시나리오 파악
  • 개별 폴드 성능 패턴: 데이터 특성을 이해하는 데 도움
  • 성능 편차가 큰 경우: 모델 재검토 또는 앙상블 방법을 고려
K폴드교차검증머신러닝모델검증하이퍼파라미터튜닝