거래 1,000건 중 실제 사기가 20건(2%)인 데이터에서 모델이 15건을 사기라고 예측했고, 그중 12건이 진짜였다고 가정한다.
실제 사기(20) 실제 정상(980)예측 사기(15) TP = 12 FP = 3예측 정상(985) FN = 8 TN = 977
지표
계산
값
읽는 법
정확도
(12+977)/1000
0.989
높아 보이지만 의미가 거의 없다
정밀도
12/(12+3)
0.80
사기라고 알린 것 중 80%가 진짜
재현율
12/(12+8)
0.60
실제 사기의 60%만 잡았다 — 8건 놓침
F1
2×0.8×0.6/(0.8+0.6)
≈0.686
둘의 균형점
비교 기준: "전부 정상"이라 찍는 모델의 정확도는 0.98이다. 즉 정확도 0.989는 "아무것도 안 하는 모델보다 0.9%p 좋다"는 뜻밖에 안 된다. 반면 재현율 0.60은 실제 개선 폭을 정직하게 보여 준다.
정밀도와 재현율은 본질적으로 트레이드오프 관계다. 분류 임계값을 낮추면 더 많이 양성으로 분류해 재현율은 오르지만 거짓양성도 늘어 정밀도가 떨어진다. 이 곡선 전체를 보는 게 PR 곡선이고, 임계값을 바꿔가며 TPR과 FPR을 그린 게 ROC 곡선이다. AUC(곡선 아래 면적)는 "임의의 양성 샘플이 임의의 음성 샘플보다 높은 점수를 받을 확률"로, 단일 임계값에 묶이지 않은 종합 판별력을 나타낸다.
개념: 임계값은 모델이 아니라 운영 정책이다. 대부분의 분류기는 확률을 내놓고, 0.5라는 경계는 그저 관습적 기본값이다. 같은 모델이라도 임계값을 낮추면 재현율이 오르고 정밀도가 떨어진다. 즉 재학습 없이 정밀도-재현율 균형을 바꿀 수 있다. "재현율이 낮으니 모델을 다시 학습해야 한다"는 보기보다 "임계값을 조정한다"가 먼저 검토되는 이유다.
from sklearn.metrics import classification_report, confusion_matrix, roc_auc_scoreprint(confusion_matrix(y_true, y_pred))print(classification_report(y_true, y_pred)) # precision/recall/f1print("AUC:", roc_auc_score(y_true, y_prob)) # 확률 기반
⚠️ 함정: 불균형 데이터에서 "정확도 99%"를 모델이 좋다는 근거로 제시하는 보기는 함정이다. 시험에서 "사기/이상/희귀 질병" 같은 키워드가 보이면 정확도가 아니라 F1·재현율·AUC를 골라야 한다. 또한 ROC-AUC는 극심한 불균형에서 낙관적으로 보일 수 있어, 양성이 매우 희귀하면 AUC-PR(정밀도-재현율 곡선)이 더 정직하다.
직관: 큰 오차를 강하게 벌하고 싶으면 RMSE, 이상치 영향을 줄이고 싶으면 MAE. 예측값이 실제값을 얼마나 설명하는지는 R².
숫자로 보면 차이가 분명하다. 5건의 예측 오차가 1, 1, 1, 1, 10이라고 가정한다.
지표
계산
값
MAE
(1+1+1+1+10)/5
2.8
MSE
(1+1+1+1+100)/5
20.8
RMSE
√20.8
≈4.56
오차 10짜리 한 건이 MAE에는 10만큼, MSE에는 100만큼 기여한다 → RMSE가 이상치 한 건에 크게 흔들린다.
MAPE 주의: 실제값이 0이거나 0에 가까우면 백분율 오차가 폭발한다. 수요가 0인 날이 섞인 데이터에는 부적합하다.
R² 주의: 특성을 계속 추가하면 값이 올라가는 성질이 있어, 특성 수가 다른 모델끼리 비교할 때는 조정된 R²를 함께 본다.
RMSE가 MAE보다 이상치에 민감한 건 오차를 제곱하기 때문이다. 오차 10인 한 점은 RMSE에선 100으로, MAE에선 10으로 기여한다. 그래서 큰 오차가 치명적인 문제(예: 수요 예측에서 대량 결품)는 RMSE를, 모든 오차를 균등하게 보고 싶은 문제는 MAE를 쓴다. 이는 손실함수 선택과도 직결된다 — RMSE를 줄이도록 학습하면 모델이 큰 오차를 피하는 쪽으로 치우친다.
모델 평가의 다른 축은 일반화다. 학습 데이터에만 잘 맞고 새 데이터에서 무너지면 과적합(overfitting)이다.
상태
학습 성능
검증/테스트 성능
진단
과소적합 (underfit)
낮음
낮음
모델이 너무 단순/덜 학습 (high bias)
적합
높음
높음
균형
과적합 (overfit)
매우 높음
낮음
모델이 학습 데이터를 외움 (high variance)
진단: 학습 성능은 좋은데 검증 성능이 나쁘고 둘의 격차가 크면 과적합. 둘 다 나쁘면 과소적합.
학습 곡선으로 보면 세 상태가 한눈에 갈린다.
검증 손실이 바닥을 찍고 다시 올라가는 지점이 조기 종료(early stopping)의 기준점이다.
학습·검증이 둘 다 높은 채로 평평하면 모델을 키우거나 더 학습시켜야 한다(과소적합).
과적합 완화:
더 많은 데이터, 데이터 증강
정규화(L1/L2), 드롭아웃
모델 복잡도 축소, 조기 종료(early stopping)
특성 수 줄이기
과소적합 완화:
모델 복잡도 증가, 더 오래 학습
더 나은 특성 추가, 정규화 완화
한 팀이 이미지 분류 모델을 학습했더니 학습 정확도 99%, 검증 정확도 70%로 큰 격차가 났다. 전형적 과적합. 데이터 증강(회전·플립)과 드롭아웃을 추가하고 조기 종료를 걸자 학습 95%/검증 91%로 격차가 줄며 일반화가 좋아졌다. 교훈: 학습-검증 격차가 과적합의 핵심 신호이고, 정규화·증강·조기 종료가 표준 처방이다.
from sklearn.model_selection import StratifiedKFold, TimeSeriesSplit, cross_val_score# 불균형 분류: fold마다 클래스 비율 유지cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)print(cross_val_score(model, X, y, cv=cv, scoring='f1').mean())# 시계열: 항상 과거로 학습하고 미래로 검증tscv = TimeSeriesSplit(n_splits=5)print(cross_val_score(model, X, y, cv=tscv, scoring='neg_root_mean_squared_error').mean())
교차검증의 가치는 평가 분산을 줄이는 데 있다. 한 번의 train/test 분할은 그 분할에 운이 따른 추정치(고분산)다. k-fold는 여러 분할의 평균을 내 추정의 분산을 낮추고, 데이터를 학습·검증에 모두 활용해 적은 데이터를 효율적으로 쓴다. 다만 k가 클수록 학습을 k번 반복해 비용이 늘고, 시계열처럼 순서가 의미 있는 데이터에선 무작위 분할이 미래 정보를 흘려 평가를 부풀린다는 점을 주의한다.
"검증 점수는 훌륭한데 운영에서 무너진다"의 대부분은 과적합이 아니라 누수(leakage)다. 지표 선택보다 먼저 의심해야 하는 항목이다.
증상
원인
조치
검증 정확도가 비현실적으로 높다(0.99+)
정답에서 파생된 특성이 섞임(타깃 누수)
특성 생성 시점을 예측 시점 기준으로 재정의
교차검증은 좋은데 운영 성능이 급락
전체 데이터로 스케일러·인코더를 먼저 학습(fit)
분할 이후 학습 fold에서만 fit, 검증엔 transform만
시계열 모델이 백테스트에서만 잘 맞음
무작위 k-fold로 미래 데이터가 학습에 포함
time-series split으로 순서 유지
같은 고객·환자의 기록이 학습·검증에 나뉘어 들어감
그룹 누수
그룹 단위 분할(같은 개체는 한쪽에만)
오버샘플링 후 점수가 급등
검증 세트까지 오버샘플링해 중복 샘플이 양쪽에 존재
분할 → 학습 세트에만 리샘플링
⚠️ 함정: 전처리(정규화·결측 대치·인코딩)를 분할 전에 전체 데이터로 수행하는 코드는 시험에서 오답 보기로 쓰이기 쉽다. 검증 세트의 분포 정보가 학습에 흘러들어 평가가 낙관적으로 부풀기 때문이다. 정답은 언제나 "분할 먼저, 전처리는 학습 세트 기준으로 학습해 검증에 적용".