분류 모델 평가에서 교차검증과 ROC/AUC를 함께 쓰는 법
교차검증, ROC/AUC, 혼동행렬, F1 Score를 활용해 분류 모델의 일반화 성능과 운영 임계값을 검증하는 방법
2026-08-14 · 최초 발행 2025-10-14
평가 지표를 운영 결정으로 연결하려면
분류 모델의 성능은 단일 정확도만으로 판단하기 어렵다. 데이터 분할 방식에 따라 결과가 흔들릴 수 있고, 실제 운영에서는 오탐과 미탐의 비용이 같지 않은 경우가 많다. 교차검증, ROC/AUC, 혼동행렬, F1 Score는 각각 다른 관점에서 이 문제를 확인하기 위한 도구다.
교차검증은 데이터를 여러 폴드로 나눠 학습과 검증을 반복하면서 성능 분산을 낮추는 절차다. 대표적인 방식은 K-fold와 Leave-One-Out Cross-Validation(LOOCV)이다.
ROC 곡선은 임계값 변화에 따른 TPR(민감도)과 FPR(1-특이도)의 관계를 나타낸다. AUC는 이 곡선 아래 면적으로, 분류기의 임계값 불변 평균 성능을 측정한다.
혼동행렬은 실제값과 예측값을 교차 집계해 TP, FP, FN, TN을 보여 준다. 오탐과 미탐이 어디에서 발생하는지 파악하고 비용 민감 임계값을 정하는 근거가 된다.
F1 Score는 정밀도(Precision)와 재현율(Recall)의 조화평균이다. 클래스 불균형 상황에서는 정확도보다 신뢰할 수 있는 단일 요약 지표가 될 수 있다.
데이터 규모와 목적에 맞춘 검증 방식
K-fold는 일반적으로 K=5~10을 적용한다. 성능 분산을 낮추면서 계산비용을 조절할 수 있으며, 분류 문제에서는 계층화(Stratified)를 적용해 클래스 비율을 유지하는 편이 적합하다.
LOOCV는 표본 수가 매우 적을 때 편향을 줄이는 데 유리하지만, 분산과 계산비용이 크다. 실무에서는 소형 데이터나 모델 비교를 위한 보조 수단으로 쓰는 편이 낫다.
ROC/AUC는 임계값과 독립적으로 성능을 요약한다. 클래스 불균형에서도 비교적 견고하지만, 양성 클래스가 희소하다면 PR-AUC를 함께 확인해야 한다. AUC는 무작위 양성-음성 쌍을 올바르게 순위화할 확률로 해석할 수 있다. 이 값과 운영 임계값 선택은 분리해서 판단한다.
혼동행렬은 FP와 FN의 비용이 비대칭인 환경에서 특히 중요하다. 임계값, 가중치, 비용 함수를 설계할 때 오류 유형을 직접 확인할 수 있다. 멀티클래스 문제에서는 행과 열 단위로 오류가 집중되는 구간을 찾아 데이터 증강이나 클래스 가중치 조정 지점을 정할 수 있다.
정밀도·재현율·F1 Score는 임계값에 민감하므로 운영 점(Operating Point)을 정하는 핵심 지표다. 클래스 불균형 환경에서는 교차검증 기반 평균값을 사용해 변동성을 낮추는 방식이 권장된다. 멀티클래스 집계는 micro(표본 가중), macro(클래스 균등), weighted(클래스 비율 가중) 중 현업 KPI에 맞는 방식을 명시해야 한다.
비용 민감 최적화에서는 비용행렬을 기반으로 기대손실이 가장 작은 임계값을 찾는다. 의료·금융 도메인에서 권장되는 방식이다. 확률 보정에는 Platt scaling이나 Isotonic 회귀를 적용할 수 있으며, 경계 임계값 근처의 안정성을 높이는 데 활용한다.
검증 방식별 선택 기준
| 방법 | 성능(추정 신뢰도) | 확장성(계산비용) | 일관성(재현성) | 안정성(분산) | 운영 편의 |
|---|---|---|---|---|---|
| Holdout | 낮음 | 높음 | 낮음 | 낮음 | 높음 |
| K-fold | 중~높음 | 중간 | 중~높음 | 중~높음 | 중간 |
| LOOCV | 중간 | 낮음 | 중간 | 낮음 | 낮음 |
주: “안정성(분산)”은 평가 결과의 변동성 역지표로, 높음은 분산 낮음을 의미한다.
학습부터 보고서까지의 평가 흐름
평가 파이프라인에는 데이터셋, 목표 변수와 클래스 비율, 도메인 비용 구조가 입력으로 들어간다. 스케일링과 인코딩 같은 전처리 스키마는 데이터 누수를 막을 수 있도록 파이프라인 안에 정의해야 한다.
분류 문제에는 Stratified K-fold를 적용하고, 시계열 데이터는 TimeSeriesSplit을 사용한다. 각 폴드에서 학습한 뒤 예측 확률을 얻고 지표를 계산한다. 이후 임계값을 스윕해 F1 최적점 또는 비용이 최소인 임계값을 정한다.
출력에는 교차검증 평균 ROC/AUC, F1, 혼동행렬, 임계값이 포함된다. 운영 보고서에는 기대 성능 범위(평균±표준편차), 오류 유형, 리스크와 개선 포인트를 담는다.
클래스 불균형이 극심하다면 Stratified를 필수로 적용하고, PR-AUC와 클래스 가중 또는 리샘플링을 병행한다. 전처리는 전체 데이터를 기준으로 적합하지 않고, 교차검증 안에서 각 폴드의 학습 데이터로 적합해야 한다. 데이터 쉬프트가 우려되면 시간순 검증, 최근 데이터 가중, 드리프트 모니터링 지표를 함께 사용한다.
실행 가능한 평가 코드
전제조건: Python 3.9+, scikit-learn >= 1.2, numpy, matplotlib(optional)
# pip install scikit-learn numpy matplotlib
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import StratifiedKFold, cross_val_predict, LeaveOneOut
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score, roc_curve, confusion_matrix, f1_score, precision_recall_fscore_support
# 1) 데이터 로드
X, y = load_breast_cancer(return_X_y=True)
# 2) 모델 및 교차검증 설정
model = LogisticRegression(max_iter=1000, solver="liblinear")
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
# 3) 교차검증 예측 확률(폴드 외부 예측)
proba = cross_val_predict(model, X, y, cv=cv, method="predict_proba")[:, 1]
# 4) ROC/AUC
auc = roc_auc_score(y, proba)
fpr, tpr, thresholds = roc_curve(y, proba)
print(f"AUC = {auc:.4f}")
# 5) 임계값 스윕으로 F1 최적화
ts = np.linspace(0, 1, 101)
f1s = []
for t in ts:
yhat = (proba >= t).astype(int)
f1s.append(f1_score(y, yhat))
best_idx = int(np.argmax(f1s))
best_t = ts[best_idx]
print(f"Best threshold by F1 = {best_t:.2f}, F1 = {f1s[best_idx]:.4f}")
# 6) 최적 임계값에서 혼동행렬/정밀도/재현율/F1
y_pred = (proba >= best_t).astype(int)
cm = confusion_matrix(y, y_pred)
prec, rec, f1, _ = precision_recall_fscore_support(y, y_pred, average="binary")
print("Confusion Matrix:\n", cm)
print(f"Precision={prec:.4f}, Recall={rec:.4f}, F1={f1:.4f}")
# 7) 소형 데이터에서만 권장: LOOCV 예시(계산 비용 큼)
# loo = LeaveOneOut()
# auc_loo = np.mean(
# cross_val_predict(model, X, y, cv=loo, method="predict_proba")[:, 1] # 확률 예측
# )
# 주: LOOCV는 n회 학습 수행. 대규모 데이터에 비권장.
멀티클래스 문제에서는 roc_auc_score(..., multi_class="ovr" 또는 "ovo")를 사용하고, F1은 average 인자(micro/macro/weighted)를 명시한다. 확률 보정은 CalibratedClassifierCV(base_estimator=model, method="isotonic" 또는 "sigmoid")로 적용할 수 있다.
평가 설계에서 피하기 어려운 트레이드오프
전처리부터 모델까지를 Sklearn Pipeline 안에 넣으면 교차검증 과정에서 누수를 막을 수 있다. 파이프라인은 복잡해지지만, 재현 가능성과 신뢰도는 높아진다.
분류에는 Stratified K-fold, 시계열에는 TimeSeriesSplit을 적용한다. 시계열 분할은 훈련 데이터가 줄어드는 대신 현실적인 성능 추정을 제공한다.
임계값과 비용을 최적화할 때는 혼동행렬을 바탕으로 비용행렬을 최소화하고, F1 또는 PR-AUC를 함께 본다. 정확도 중심 평가는 해석이 단순하지만, 운영 손실 최소화와는 다른 결과를 낼 수 있다.
하이퍼파라미터 탐색과 평가는 Nested CV로 분리한다. 계산비용은 커지지만 과적합을 막고 모델을 공정하게 비교할 수 있다.
도메인별로 달라지는 우선순위
의료 진단 모델에서는 재현율을 우선하고 비용행렬을 적용한다. 임계값을 상향 조정해 미탐을 최소화한다.
금융 사기 탐지는 극단적 불균형을 전제로 하므로 PR-AUC와 F1 최적화를 사용하고, 경보 처리 비용을 반영한다.
마케팅 전환 예측에서는 AUC로 모델을 랭킹하고, 비즈니스 KPI에 맞춰 임계값을 조정한 뒤 리프트 분석과 연결한다.
평가 체계가 만드는 변화
K-fold를 도입하면 Holdout 대비 성능 추정 분산이 2040% 감소 가능하다. 임계값 최적화로 F1/PR-AUC 최대 515%p 향상을 기대할 수 있으며, 이는 도메인과 데이터에 의존한다.
오류 유형이 명확해지면 운영과 품질 개선을 반복하는 루프를 만들 수 있다. 데이터 쉬프트에 대응하는 능력과 재현 가능한 모델 거버넌스도 함께 갖출 수 있다.