교차 검증
Cross-Validation
데이터를 나눠 모델 성능 평가. K-fold가 대표적.
Cross-Validation
데이터를 나눠 모델 성능 평가. K-fold가 대표적.
교차 검증(Cross-Validation)은 한정된 데이터에서 모델의 일반화 성능을 더 신뢰성 있게 평가하기 위한 기법입니다. 단순히 데이터를 학습/테스트로 한 번 나누는 것과 달리, 여러 번의 분할과 평가를 수행하여 성능의 평균과 분산을 측정합니다. 이를 통해 특정 데이터 분할에 의한 우연한 결과를 방지하고 모델 성능을 보다 정확하게 추정할 수 있습니다.
가장 널리 사용되는 방법은 K-Fold 교차 검증입니다. 전체 데이터를 K개의 동일한 크기의 폴드(fold)로 나누고, 각 반복에서 1개 폴드를 검증용으로, 나머지 K-1개를 학습용으로 사용합니다. K번의 학습과 평가를 반복하여 K개의 성능 점수를 얻고, 이들의 평균을 최종 성능으로 사용합니다. 일반적으로 K=5 또는 K=10이 많이 사용됩니다.
교차 검증의 변형으로 Stratified K-Fold, Leave-One-Out(LOO), Time Series Split 등이 있습니다. Stratified K-Fold는 분류 문제에서 각 폴드에 클래스 비율을 동일하게 유지합니다. LOO는 K를 데이터 개수와 같게 설정하여 하나의 샘플만 검증에 사용하는 극단적인 방식입니다. Time Series Split은 시계열 데이터에서 미래 데이터가 과거를 학습하는 데이터 누수를 방지합니다.
교차 검증은 하이퍼파라미터 튜닝에도 활용됩니다. GridSearchCV나 RandomizedSearchCV는 여러 하이퍼파라미터 조합에 대해 교차 검증을 수행하여 최적 조합을 찾습니다. 다만 교차 검증은 모델을 K번 학습해야 하므로 계산 비용이 증가합니다. 데이터가 충분히 크다면 단순 홀드아웃(train/valid/test split)도 유효한 대안입니다.
Scikit-learn의 다양한 교차 검증 기법과 하이퍼파라미터 튜닝 예제입니다.
# pip install scikit-learn
from sklearn.datasets import load_iris
from sklearn.model_selection import (
cross_val_score, KFold, StratifiedKFold,
GridSearchCV, cross_validate
)
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
import numpy as np
# 데이터 로드
X, y = load_iris(return_X_y=True)
# 1. 기본 K-Fold 교차 검증
model = RandomForestClassifier(n_estimators=100, random_state=42)
scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')
print("=== K-Fold 교차 검증 (K=5) ===")
print(f"각 폴드 점수: {scores}")
print(f"평균 정확도: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})")
# 2. Stratified K-Fold (분류 문제에 권장)
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores_stratified = cross_val_score(model, X, y, cv=skf, scoring='accuracy')
print("\n=== Stratified K-Fold 교차 검증 ===")
print(f"평균 정확도: {scores_stratified.mean():.4f} (+/- {scores_stratified.std() * 2:.4f})")
# 3. 다중 메트릭 평가
scoring = ['accuracy', 'precision_macro', 'recall_macro', 'f1_macro']
results = cross_validate(model, X, y, cv=5, scoring=scoring, return_train_score=True)
print("\n=== 다중 메트릭 교차 검증 ===")
for metric in scoring:
test_key = f'test_{metric}'
print(f"{metric}: {results[test_key].mean():.4f} (+/- {results[test_key].std() * 2:.4f})")
# 4. GridSearchCV로 하이퍼파라미터 튜닝
param_grid = {
'C': [0.1, 1, 10],
'kernel': ['rbf', 'linear'],
'gamma': ['scale', 'auto']
}
svc = SVC(random_state=42)
grid_search = GridSearchCV(svc, param_grid, cv=5, scoring='accuracy', n_jobs=-1)
grid_search.fit(X, y)
print("\n=== GridSearchCV 결과 ===")
print(f"최적 하이퍼파라미터: {grid_search.best_params_}")
print(f"최고 교차 검증 점수: {grid_search.best_score_:.4f}")
# 5. 각 폴드별 상세 결과
print("\n=== 폴드별 상세 결과 ===")
cv_results = grid_search.cv_results_
best_idx = grid_search.best_index_
for i in range(5):
print(f"Fold {i+1}: {cv_results[f'split{i}_test_score'][best_idx]:.4f}")
# 결과 예시:
# === K-Fold 교차 검증 (K=5) ===
# 각 폴드 점수: [0.967 0.967 0.933 0.967 1.0]
# 평균 정확도: 0.9667 (+/- 0.0422)