026 교차 검증 설정 - n_splits
키워드: 교차 검증, n_splits, cross validation
개요
교차 검증(Cross Validation)은 모델의 일반화 성능을 평가하는 핵심 기법입니다. FLAML에서는 n_splits 파라미터로 교차 검증의 폴드 수를 조절할 수 있습니다.
실습 환경
- Python 버전: 3.11 권장
- 필요 패키지:
flaml[automl], scikit-learn
pip install flaml[automl] scikit-learn
교차 검증이란?
기본 개념
데이터를 여러 부분으로 나누어 학습과 검증을 반복하는 기법입니다.
import numpy as np
from sklearn.model_selection import KFold
# 026 예시 데이터
X = np.arange(10).reshape(10, 1)
y = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])
# 5-Fold 교차 검증
kf = KFold(n_splits=5, shuffle=True, random_state=42)
print("5-Fold 교차 검증:")
for fold, (train_idx, val_idx) in enumerate(kf.split(X), 1):
print(f" Fold {fold}: 학습={train_idx}, 검증={val_idx}")
실행 결과
5-Fold 교차 검증:
Fold 1: 학습=[0 2 3 4 5 6 8 9], 검증=[1 7]
Fold 2: 학습=[0 1 2 3 5 7 8 9], 검증=[4 6]
Fold 3: 학습=[0 1 3 4 6 7 8 9], 검증=[2 5]
Fold 4: 학습=[1 2 4 5 6 7 8 9], 검증=[0 3]
Fold 5: 학습=[0 1 2 3 4 5 6 7], 검증=[8 9]
왜 교차 검증을 사용하나?
# 026 단순 Train/Test 분할의 문제점
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=100, n_features=10, random_state=42)
# 026 같은 데이터, 다른 random_state
scores = []
for seed in range(10):
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=seed
)
# 간단한 모델로 테스트
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X_train, y_train)
scores.append(model.score(X_test, y_test))
print(f"분할에 따른 점수 변동:")
print(f" 최소: {min(scores):.4f}")
print(f" 최대: {max(scores):.4f}")
print(f" 차이: {max(scores) - min(scores):.4f}")
→ 단순 분할은 분할 방식에 따라 성능이 크게 달라질 수 있음
FLAML에서 n_splits 설정
기본 사용법
from flaml import AutoML
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
# 026 데이터 준비
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 026 n_splits=5 (기본값)
automl_5fold = AutoML()
automl_5fold.fit(
X_train, y_train,
task="classification",
time_budget=30,
metric="accuracy",
n_splits=5, # 5-Fold CV
verbose=0
)
print(f"5-Fold CV 결과:")
print(f" 최적 모델: {automl_5fold.best_estimator}")
print(f" 검증 점수: {1 - automl_5fold.best_loss:.4f}")
n_splits 값에 따른 비교
# 026 다양한 n_splits 테스트
results = {}
for n_splits in [3, 5, 10]:
automl = AutoML()
automl.fit(
X_train, y_train,
task="classification",
time_budget=30,
metric="accuracy",
n_splits=n_splits,
seed=42,
verbose=0
)
# 테스트 성능
test_score = automl.score(X_test, y_test)
results[n_splits] = {
'val_score': 1 - automl.best_loss,
'test_score': test_score,
'model': automl.best_estimator
}
print("n_splits별 성능 비교:")
print("-" * 50)
print(f"{'n_splits':<10} {'검증 점수':<15} {'테스트 점수':<15}")
print("-" * 50)
for n, r in results.items():
print(f"{n:<10} {r['val_score']:<15.4f} {r['test_score']:<15.4f}")
n_splits 선택 가이드
일반적인 권장값
| 데이터 크기 | 권장 n_splits | 이유 |
|---|---|---|
| 작음 (< 1000) | 5~10 | 검증 데이터 확보 |
| 중간 (1000~10000) | 5 | 균형 |
| 큼 (> 10000) | 3~5 | 학습 시간 고려 |
n_splits 증가의 장단점
# 026 장점: 더 안정적인 성능 추정
# 026 단점: 학습 시간 증가
import time
for n_splits in [3, 5, 10]:
automl = AutoML()
start = time.time()
automl.fit(
X_train, y_train,
task="classification",
time_budget=30,
n_splits=n_splits,
verbose=0
)
elapsed = time.time() - start
print(f"n_splits={n_splits}: {elapsed:.1f}초")
계층화 교차 검증
분류에서 자동 적용
FLAML은 분류 문제에서 Stratified K-Fold를 자동으로 사용합니다.
from sklearn.model_selection import StratifiedKFold
# 026 Stratified: 각 폴드에서 클래스 비율 유지
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
# 026 불균형 데이터 예시
y_imbalanced = np.array([0]*90 + [1]*10)
print("Stratified K-Fold (불균형 데이터):")
for fold, (train_idx, val_idx) in enumerate(skf.split(np.zeros(100), y_imbalanced), 1):
train_ratio = y_imbalanced[train_idx].mean()
val_ratio = y_imbalanced[val_idx].mean()
print(f" Fold {fold}: 학습 클래스1 비율={train_ratio:.2f}, 검증 클래스1 비율={val_ratio:.2f}")
실행 결과
Stratified K-Fold (불균형 데이터):
Fold 1: 학습 클래스1 비율=0.10, 검증 클래스1 비율=0.10
Fold 2: 학습 클래스1 비율=0.10, 검증 클래스1 비율=0.10
Fold 3: 학습 클래스1 비율=0.10, 검증 클래스1 비율=0.10
Fold 4: 학습 클래스1 비율=0.10, 검증 클래스1 비율=0.10
Fold 5: 학습 클래스1 비율=0.10, 검증 클래스1 비율=0.10
특수한 교차 검증
split_type 파라미터
# 026 시계열 데이터용 교차 검증
automl_time = AutoML()
automl_time.fit(
X_train, y_train,
task="classification",
time_budget=30,
n_splits=5,
split_type="time", # 시계열용 분할
verbose=0
)
# 026 그룹별 분할 (같은 그룹이 학습/검증에 섞이지 않음)
groups = np.repeat(np.arange(20), len(X_train) // 20 + 1)[:len(X_train)]
automl_group = AutoML()
automl_group.fit(
X_train, y_train,
task="classification",
time_budget=30,
n_splits=5,
split_type="group",
groups=groups,
verbose=0
)
Leave-One-Out (LOO)
극단적인 경우
# 026 n_splits = 샘플 수 → Leave-One-Out
# 026 작은 데이터에서만 사용 권장
from sklearn.model_selection import LeaveOneOut
# 026 아주 작은 데이터셋 예시
X_small = X_train[:20]
y_small = y_train[:20]
automl_loo = AutoML()
automl_loo.fit(
X_small, y_small,
task="classification",
time_budget=60,
n_splits=len(X_small), # LOO
verbose=0
)
print(f"LOO 검증 점수: {1 - automl_loo.best_loss:.4f}")
실전 예제
데이터 크기별 최적 설정
def get_optimal_n_splits(n_samples):
"""데이터 크기에 따른 권장 n_splits"""
if n_samples < 100:
return min(n_samples, 10) # 작은 데이터: 최대한 많이
elif n_samples < 1000:
return 10
elif n_samples < 10000:
return 5
else:
return 3 # 큰 데이터: 시간 절약
# 026 테스트
for n in [50, 500, 5000, 50000]:
print(f"샘플 수 {n}: n_splits={get_optimal_n_splits(n)} 권장")
안정적인 성능 추정
from sklearn.metrics import accuracy_score
import numpy as np
# 026 여러 번 교차 검증 실행하여 분산 확인
cv_scores = []
for seed in range(5):
automl = AutoML()
automl.fit(
X_train, y_train,
task="classification",
time_budget=20,
n_splits=5,
seed=seed,
verbose=0
)
cv_scores.append(1 - automl.best_loss)
print(f"5회 실행 결과:")
print(f" 평균: {np.mean(cv_scores):.4f}")
print(f" 표준편차: {np.std(cv_scores):.4f}")
print(f" 범위: {min(cv_scores):.4f} ~ {max(cv_scores):.4f}")
정리
- n_splits는 교차 검증의 폴드 수를 설정합니다.
- 기본값은 5이며, 대부분의 경우 적절합니다.
- 작은 데이터에서는 n_splits를 늘려 검증 안정성을 높입니다.
- 큰 데이터에서는 n_splits를 줄여 학습 시간을 단축합니다.
- 분류에서는 Stratified K-Fold가 자동 적용됩니다.
- 시계열/그룹 데이터는 split_type 파라미터를 활용합니다.
다음 글 예고
다음 글에서는 조기 종료 - early_stop에 대해 알아보겠습니다. 불필요한 학습을 줄여 효율적으로 최적 모델을 찾는 방법을 다룹니다.
FLAML AutoML 마스터 시리즈 #026