1 왜 Accuracy 하나로는 부족한가
분류 모델을 평가할 때 가장 먼저 떠오르는 지표는 Accuracy(정확도)다.
\[\text{Accuracy} = \frac{\text{올바르게 분류한 수}}{\text{전체 샘플 수}}\]
그런데 암 진단 모델을 만든다고 하자. 실제 양성(암 환자)이 1%인 데이터에서, 모든 샘플을 “음성”으로 예측하면 Accuracy는 99%다. 그러나 이 모델은 환자를 한 명도 찾지 못하는 쓸모없는 모델이다.
Accuracy가 실패하는 이유: 클래스 불균형(class imbalance) 상황에서 다수 클래스를 맞추는 것만으로도 높은 수치가 나오기 때문이다. 더 정밀한 지표가 필요하다.
2 혼동 행렬 (Confusion Matrix)
모든 분류 성능 지표의 출발점은 혼동 행렬이다. 이진 분류를 기준으로 하면 예측과 실제 레이블의 조합으로 4가지 경우가 생긴다.
| 예측: 양성 (Positive) | 예측: 음성 (Negative) | |
|---|---|---|
| 실제: 양성 (Positive) | TP (True Positive) | FN (False Negative) |
| 실제: 음성 (Negative) | FP (False Positive) | TN (True Negative) |
- TP: 실제 양성을 양성으로 올바르게 예측
- TN: 실제 음성을 음성으로 올바르게 예측
- FP: 실제 음성인데 양성으로 잘못 예측 → 제1종 오류(Type I Error)
- FN: 실제 양성인데 음성으로 잘못 예측 → 제2종 오류(Type II Error)
FP와 FN의 비용은 다르다.
암 진단을 예로 들면:
- FN (환자를 정상으로 판정): 암 환자가 치료 기회를 놓친다. 환자가 가장 싫어한다. 생명과 직결되는 치명적 오류다.
- FP (정상인을 환자로 판정): 불필요한 조직 검사, 수술, 항암 치료로 이어진다. 의사(와 병원)가 더 싫어한다. 의료 소송·과잉 진료 리스크가 생기기 때문이다.
암 진단에서는 FN의 대가가 FP보다 훨씬 크므로, 일반적으로 Recall(Sensitivity)을 극대화하고 FP는 어느 정도 감수하는 방향으로 모델을 튜닝한다.
3 통계적 오류 유형과 ML 지표의 연결
통계학의 가설 검정과 ML 분류는 동일한 구조를 공유한다.
| 구분 | 통계 가설검정 | 의학 진단 | ML 분류 |
|---|---|---|---|
| 귀무가설 (\(H_0\)) | 효과 없음 | 정상 | 음성 클래스 |
| 대립가설 (\(H_1\)) | 효과 있음 | 환자 | 양성 클래스 |
| 제1종 오류 (\(\alpha\)) | \(H_0\) 참인데 기각 | 정상인을 환자로 | FP (False Positive) |
| 제2종 오류 (\(\beta\)) | \(H_0\) 거짓인데 채택 | 환자를 정상으로 | FN (False Negative) |
| 검정력 (Power, \(1-\beta\)) | 효과를 올바르게 탐지 | 환자를 올바르게 탐지 | TP Rate (Recall) |
| 유의 수준 (\(\alpha\)) | FP를 허용할 최대치 | 정상인 오진 허용 한계 | FP Rate 상한 |
이 대응 관계를 이해하면 ML 지표가 왜 그런 이름을 갖는지, 서로 어떻게 충돌하는지 명확해진다.
4 핵심 성능 지표
4.1 Precision (정밀도)
\[\text{Precision} = \frac{TP}{TP + FP}\]
의미: 양성이라고 예측한 것 중 실제로 양성인 비율이다. “내가 양성이라고 외쳤을 때, 얼마나 자주 맞는가?”
이름의 직관: precision은 영어로 “정밀한, 딱 맞아떨어지는”이라는 뜻이다. 과녁을 향해 화살 10발을 쐈을 때, 내가 맞혔다고 표시한 곳에 실제로 꽂힌 비율을 생각하면 된다. 헛짚지 않는 능력이다. 한국어 정밀도(精密度)는 “정교하고(精) 세밀하게(密) 맞추는 정도(度)”다.
\[1 - \text{Precision} = \frac{FP}{TP+FP} = \text{FDR (False Discovery Rate)}\]
Precision이 낮다는 것은 FDR이 높다는 것, 즉 헛짚는 경우가 많다는 의미다.
Precision을 높이려면: Threshold를 높여 확실한 경우에만 양성이라 한다. 그러면 FP는 줄지만 FN이 늘어 Recall이 낮아진다.
4.2 Recall (재현율) = Sensitivity (민감도) = Power (검정력)
\[\text{Recall} = \text{Sensitivity} = 1 - \beta = \frac{TP}{TP + FN}\]
의미: 실제 양성 중 올바르게 잡은 비율이다. “실제 양성을 얼마나 빠뜨리지 않고 찾아내는가?”
이름의 직관: recall은 영어로 “다시 불러오다(call back)”, “기억해내다”는 뜻이다. 1970년대 도서관 정보 검색 시스템을 평가할 때 처음 쓰인 개념이다.
도서관에 “암” 관련 논문이 실제로 100편 있다. 검색 시스템이 그 중 70편을 불러왔다(recalled). → Recall = 70/100 = 0.7
즉, “존재하는 것들을 얼마나 기억해서 불러왔는가”의 비율이다. 한국어 재현율(再現率)은 “다시(再) 나타나게(現) 하는 비율(率)”이다. 실제로 존재하는 것들을 얼마나 다시 나타나게 했는가를 의미한다.
세 이름이 같은 수식을 가리키는 이유: - Recall: 정보 검색 — 존재하는 문서를 불러오는 능력 - Sensitivity(민감도): 의학 — 이상 신호에 얼마나 예민하게 반응하는가 - Power(검정력): 통계 — 실제 효과를 감지하는 힘
Recall이 낮다는 것은 \(\beta\)(제2종 오류)가 크다는 것, 즉 실제 양성을 많이 놓친다는 의미다.
Recall을 높이려면: Threshold를 낮춰 더 적극적으로 양성이라 한다. 그러면 FN은 줄지만 FP가 늘어 Precision이 낮아진다.
4.3 Specificity (특이도)
\[\text{Specificity} = \frac{TN}{TN + FP} = 1 - \text{FPR}\]
의미: 실제 음성 중 올바르게 음성으로 잡은 비율이다. “정상인을 정상으로 올바르게 판정하는가?”
이름의 직관: specificity는 “특별히 구별해내는 능력”에서 왔다. 음성(정상)을 정상으로 특이하게(특별히) 가려내는 능력이다. “이 검사는 정상인을 정상으로 특별히 잘 판별한다”는 의미다. 한국어 특이도(特異度)는 “특별히(特) 다르게(異) 구별하는 정도(度)”로 이해하면 된다.
통계학의 \(1 - \alpha\)에 해당한다. Specificity가 낮으면 제1종 오류(\(\alpha\))가 크다.
4.4 NPV (Negative Predictive Value)
\[\text{NPV} = \frac{TN}{TN + FN}\]
의미: 음성이라고 예측한 것 중 실제로 음성인 비율이다. Precision의 음성 버전이다. “음성이라고 했을 때, 얼마나 믿을 수 있는가?”
4.5 전체 지표 요약
| 지표 | 수식 | 분모 | 관점 | 통계 대응 |
|---|---|---|---|---|
| Accuracy | \((TP+TN)/(P+N)\) | 전체 | 전반적 정확도 | — |
| Precision | \(TP/(TP+FP)\) | 예측 양성 수 | 예측의 신뢰도 | \(1 - \text{FDR}\) |
| Recall | \(TP/(TP+FN)\) | 실제 양성 수 | 양성 탐지력 | Power (\(1-\beta\)) |
| Specificity | \(TN/(TN+FP)\) | 실제 음성 수 | 음성 탐지력 | \(1 - \alpha\) |
| NPV | \(TN/(TN+FN)\) | 예측 음성 수 | 음성 판정 신뢰도 | — |
| FPR | \(FP/(FP+TN)\) | 실제 음성 수 | 오경보 비율 | \(\alpha\) |
| FNR | \(FN/(TP+FN)\) | 실제 양성 수 | 탐지 실패 비율 | \(\beta\) |
5 F1 Score와 F-beta Score
5.1 F1 Score
\[F1 = \frac{2 \cdot \text{Precision} \cdot \text{Recall}}{\text{Precision} + \text{Recall}} = \frac{2}{\dfrac{1}{\text{Precision}} + \dfrac{1}{\text{Recall}}}\]
F1은 Precision과 Recall의 조화평균(Harmonic Mean)이다.
이름의 직관: F는 1979년 C. J. van Rijsbergen의 정보 검색 논문에서 나온 F-measure의 F다. 관례적으로 “Effectiveness(효과성)”의 약자로 여겨진다. 뒤의 숫자 1은 \(F_\beta\)에서 \(\beta = 1\)임을 뜻한다. \(\beta\)는 “Recall이 Precision보다 몇 배 중요한가”를 나타내는 파라미터이며, \(\beta = 1\)이면 둘을 동등하게 본다는 의미다.
왜 조화평균인가?
Precision과 Recall의 분자가 모두 TP로 동일하고, 분모만 다르다. 분자가 고정된 두 비율의 평균에는 조화평균이 수학적으로 올바른 선택이다 (자세한 내용은 산술·기하·조화평균 비교 참조).
또한 조화평균은 작은 값에 민감하다. 하나가 0에 가까우면 전체도 0에 수렴한다.
| 모델 | Precision | Recall | 산술평균 | F1 |
|---|---|---|---|---|
| 모델 A (편향) | 1.00 | 0.00 | 0.500 | 0.000 |
| 모델 B (반편향) | 0.00 | 1.00 | 0.500 | 0.000 |
| 모델 C (균형 낮음) | 0.50 | 0.50 | 0.500 | 0.500 |
| 모델 D (균형 높음) | 0.90 | 0.80 | 0.850 | 0.847 |
모델 A, B, C는 산술평균으로는 모두 0.5지만, F1은 전혀 다른 평가를 내린다. F1이 “둘 다 잘해야 한다”는 조건을 강제한다는 것을 알 수 있다.
F1의 한계: TN(True Negative)을 전혀 고려하지 않는다. 음성 클래스의 성능이 지표에 반영되지 않는다.
5.2 F-beta Score: Recall과 Precision의 가중치 조절
Precision과 Recall의 상대적 중요도가 다를 때 \(F_\beta\) 를 사용한다.
\[F_\beta = (1 + \beta^2) \cdot \frac{\text{Precision} \cdot \text{Recall}}{\beta^2 \cdot \text{Precision} + \text{Recall}}\]
- \(\beta > 1\): Recall에 더 많은 가중치 → 놓치는 것이 더 나쁜 상황 (암 진단, 사기 탐지)
- \(\beta < 1\): Precision에 더 많은 가중치 → 헛짚는 것이 더 나쁜 상황 (스팸 필터, 추천 시스템)
- \(\beta = 1\): F1 Score (동등한 가중치)
자주 쓰이는 값: - \(F_2\): Recall을 Precision보다 2배 중시 - \(F_{0.5}\): Precision을 Recall보다 2배 중시
\(\beta\) 설정의 직관
\(\beta\)는 “Recall이 Precision보다 몇 배 중요한가”를 나타낸다. 암 진단에서 FN(환자를 놓침)의 비용이 FP(정상인을 환자로 진단)보다 5배 크다고 판단하면 \(\beta = \sqrt{5} \approx 2.2\)를 설정할 수 있다.
6 Precision-Recall 트레이드오프
분류 모델은 내부적으로 연속적인 확률 점수(score)를 출력하고, 이를 특정 threshold 이상이면 양성으로 분류한다.
threshold를 변화시키면:
threshold 높임 (더 엄격):
양성 예측 수 ↓ → FP ↓, TP ↓
→ Precision ↑, Recall ↓ (Type I 오류 ↓, Type II 오류 ↑)
threshold 낮춤 (더 관대):
양성 예측 수 ↑ → FP ↑, TP ↑
→ Precision ↓, Recall ↑ (Type I 오류 ↑, Type II 오류 ↓)
이 관계를 그린 것이 Precision-Recall 곡선(PR Curve)이다.
통계 검정에서의 동일한 트레이드오프
통계적 가설 검정에서도 같은 구조가 나타난다.
- \(\alpha\) (유의 수준)를 낮추면: FP(제1종 오류) ↓, 하지만 Power(\(1-\beta\), Recall) ↓
- 표본 크기를 늘리면: Power ↑ (Recall ↑), \(\alpha\)는 유지
ML에서 threshold를 올리는 것은 통계에서 \(\alpha\)를 낮추는 것과 유사하고, 표본을 늘리는 것은 더 좋은 모델을 학습시키는 것에 해당한다.
7 ROC 곡선과 AUC
7.1 ROC 곡선 (Receiver Operating Characteristic Curve)
x축: FPR (False Positive Rate) \(= \alpha = \dfrac{FP}{FP+TN}\)
y축: TPR (True Positive Rate) \(= 1 - \beta = \text{Recall} = \dfrac{TP}{TP+FN}\)
threshold를 0에서 1로 변화시키면서 (FPR, TPR) 쌍을 그린 곡선이다.
- 좌상단 꼭짓점 (0, 1): 이상적인 분류기 (FPR=0, TPR=1)
- 대각선: 무작위 분류기 (AUC = 0.5)
- 곡선이 좌상단에 가까울수록 좋은 모델
7.2 AUC (Area Under the ROC Curve)
AUC는 ROC 곡선 아래의 면적이다 (\(0 \leq AUC \leq 1\)).
확률적 해석: AUC는 “무작위로 선택한 양성 샘플의 score가 무작위로 선택한 음성 샘플의 score보다 높을 확률”이다.
\[AUC = P(\text{score}_{positive} > \text{score}_{negative})\]
| AUC 값 | 해석 |
|---|---|
| 1.0 | 완벽한 분류기 |
| 0.9 ~ 1.0 | 우수 |
| 0.8 ~ 0.9 | 양호 |
| 0.7 ~ 0.8 | 보통 |
| 0.5 ~ 0.7 | 개선 필요 |
| 0.5 | 무작위 분류기 수준 |
| < 0.5 | 역전된 예측 (레이블 반전 시 개선 가능) |
AUC의 장점: Threshold에 무관하게 모델 전체의 분리 능력을 하나의 숫자로 요약한다.
AUC의 한계: 클래스 불균형이 심하면 음성 클래스가 FPR에 과도하게 영향을 미쳐 AUC가 낙관적으로 보일 수 있다.
7.3 PR-AUC (Precision-Recall AUC)
클래스 불균형이 심할 때 ROC-AUC 대신 사용한다.
x축: Recall, y축: Precision으로 그린 곡선의 면적이다. 음성 클래스가 압도적으로 많을 때, ROC-AUC는 높게 나와도 PR-AUC는 낮을 수 있다. 이 경우 PR-AUC가 더 현실적인 평가를 제공한다.
언제 PR-AUC를 우선하는가: 양성 클래스가 희귀하고 양성 탐지가 핵심인 경우 (사기 탐지, 희귀 질병 진단, 이상 탐지).
8 MCC (Matthews Correlation Coefficient)
\[MCC = \frac{TP \cdot TN - FP \cdot FN}{\sqrt{(TP+FP)(TP+FN)(TN+FP)(TN+FN)}}\]
MCC는 혼동 행렬의 모든 네 칸(TP, TN, FP, FN)을 동시에 고려하는 지표다.
- 범위: \(-1 \leq MCC \leq 1\)
- \(MCC = 1\): 완벽한 예측
- \(MCC = 0\): 무작위 예측 수준
- \(MCC = -1\): 완전히 반대로 예측
MCC의 강점: 클래스 불균형 상황에서도 균형 잡힌 평가를 제공한다. Accuracy, F1이 불균형 데이터에서 misleading한 경우에도 MCC는 실질적인 성능을 반영한다.
클래스가 1%인 데이터에서 모두 음성으로 예측하면: - Accuracy = 0.99 (높아 보임) - F1 = 0.0 (양성 예측이 없으므로) - MCC = 0.0 (무작위 예측 수준임을 정확히 반영)
9 다중 클래스 분류에서의 평균 방식
이진 분류 지표를 다중 클래스로 확장할 때 평균 방식을 선택해야 한다.
| 방식 | 계산 | 적합한 상황 |
|---|---|---|
| Macro-average | 각 클래스 지표의 단순 평균 | 모든 클래스가 동등하게 중요할 때 |
| Weighted-average | 각 클래스 지표의 샘플 수 가중 평균 | 클래스 불균형이 있고, 다수 클래스가 더 중요할 때 |
| Micro-average | 전체 TP/FP/FN을 합산 후 계산 | 개별 샘플 단위의 성능이 중요할 때 |
클래스 불균형이 있을 때 Macro-average F1은 소수 클래스의 낮은 성능을 강조하고, Weighted-average F1은 다수 클래스의 성능을 더 반영한다.
10 지표 선택 가이드
10.1 상황별 우선 지표
| 상황 | 우선 지표 | 이유 |
|---|---|---|
| 클래스 균형, 전반적 성능 | Accuracy | 단순하고 직관적 |
| 클래스 불균형, 양성 탐지 중요 | F1 / PR-AUC | TN 무시, 양성 성능에 집중 |
| FN 비용이 압도적으로 큼 (암 진단) | Recall (Sensitivity) | 놓치는 것을 최소화 |
| FP 비용이 압도적으로 큼 (스팸 필터) | Precision / Specificity | 헛짚는 것을 최소화 |
| Threshold 무관한 전체 성능 비교 | ROC-AUC | threshold-free 평가 |
| 심한 불균형 + 양성 탐지 핵심 | PR-AUC | ROC-AUC의 낙관 편향 방지 |
| 불균형에도 균형 잡힌 단일 지표 | MCC | 네 칸 모두 반영 |
| Recall/Precision 중요도 다름 | F-beta | \(\beta\)로 가중치 조절 |
10.2 의사결정 흐름
클래스 불균형이 심한가?
├── NO → Accuracy, ROC-AUC
└── YES → 양성 탐지가 핵심인가?
├── NO → MCC, Weighted F1
└── YES → FN vs FP 비용 비교
├── FN이 더 나쁨 → Recall, F2, PR-AUC
├── FP가 더 나쁨 → Precision, Specificity, F0.5
└── 동등함 → F1, PR-AUC
11 코드 예시
11.1 Python: 전체 지표 한 번에 계산
import numpy as np
from sklearn.metrics import (
confusion_matrix, classification_report,
roc_auc_score, average_precision_score,
f1_score, precision_score, recall_score,
matthews_corrcoef
)
import matplotlib.pyplot as plt
from sklearn.metrics import RocCurveDisplay, PrecisionRecallDisplay
# 예시: 실제 레이블과 예측 확률
y_true = np.array([1]*100 + [0]*900) # 불균형: 양성 10%
np.random.seed(42)
y_score = np.random.beta(2, 5, 1000) # 예측 확률
y_score[:100] += 0.3 # 양성 샘플의 score를 약간 높임
y_score = np.clip(y_score, 0, 1)
y_pred = (y_score >= 0.5).astype(int)
# 혼동 행렬
cm = confusion_matrix(y_true, y_pred)
tn, fp, fn, tp = cm.ravel()
print(f"혼동 행렬:\n{cm}")
print(f"TP={tp}, FP={fp}, FN={fn}, TN={tn}")
# 핵심 지표
precision = tp / (tp + fp)
recall = tp / (tp + fn) # = Sensitivity = Power
specificity = tn / (tn + fp) # = 1 - FPR = 1 - alpha
npv = tn / (tn + fn)
f1 = 2 * precision * recall / (precision + recall)
mcc = matthews_corrcoef(y_true, y_pred)
roc_auc = roc_auc_score(y_true, y_score)
pr_auc = average_precision_score(y_true, y_score)
print(f"\n--- 성능 지표 ---")
print(f"Precision (=1-FDR): {precision:.4f}")
print(f"Recall (=Sensitivity=Power): {recall:.4f}")
print(f"Specificity (=1-alpha): {specificity:.4f}")
print(f"NPV: {npv:.4f}")
print(f"F1 Score: {f1:.4f}")
print(f"MCC: {mcc:.4f}")
print(f"ROC-AUC: {roc_auc:.4f}")
print(f"PR-AUC: {pr_auc:.4f}")11.2 Python: F-beta Score 비교
from sklearn.metrics import fbeta_score
betas = [0.5, 1.0, 2.0, 5.0]
print(f"{'beta':>8} {'F-beta':>10} {'해석':>30}")
for beta in betas:
fb = fbeta_score(y_true, y_pred, beta=beta)
if beta < 1:
note = "Precision 중시"
elif beta == 1:
note = "균등 (= F1)"
else:
note = f"Recall {beta}배 중시"
print(f"{beta:>8.1f} {fb:>10.4f} {note:>30}")11.3 Python: ROC vs PR 곡선 비교
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# ROC 곡선
RocCurveDisplay.from_predictions(
y_true, y_score, ax=axes[0], name="모델"
)
axes[0].set_title("ROC Curve (불균형 데이터)")
# PR 곡선
PrecisionRecallDisplay.from_predictions(
y_true, y_score, ax=axes[1], name="모델"
)
axes[1].set_title("PR Curve (불균형 데이터)")
plt.tight_layout()
plt.savefig("roc_pr_comparison.png", dpi=150)
plt.show()
# 불균형 데이터에서 ROC-AUC는 낙관적으로 보이지만
# PR-AUC는 실제 양성 탐지 성능을 보수적으로 평가한다11.4 R: 분류 지표 계산
library(caret)
library(pROC)
# 혼동 행렬 및 주요 지표
set.seed(42)
n_pos <- 100; n_neg <- 900
y_true <- factor(c(rep("Positive", n_pos), rep("Negative", n_neg)))
y_score <- c(rbeta(n_pos, 3, 4) + 0.2, rbeta(n_neg, 2, 5))
y_score <- pmin(y_score, 1)
y_pred <- factor(ifelse(y_score >= 0.5, "Positive", "Negative"),
levels = c("Positive", "Negative"))
# caret 혼동 행렬 (Precision, Recall, Specificity 등 자동 계산)
cm <- confusionMatrix(y_pred, y_true, positive = "Positive")
print(cm)
# ROC-AUC
roc_obj <- roc(y_true, y_score, levels = c("Negative", "Positive"))
cat(sprintf("ROC-AUC: %.4f\n", auc(roc_obj)))
plot(roc_obj, main = "ROC Curve")12 핵심 요약
분류 지표 선택의 3대 원칙
오류 비용을 먼저 정의한다: FP와 FN 중 어느 쪽이 더 나쁜가를 먼저 결정한다. 이것이 Precision 중심인지 Recall 중심인지를 결정한다.
클래스 불균형을 확인한다: 불균형이 심하면 Accuracy와 ROC-AUC는 misleading할 수 있다. F1, PR-AUC, MCC를 우선 검토한다.
단일 지표에 의존하지 않는다: Precision, Recall, AUC를 함께 보고, 비즈니스 맥락에서 의미 있는 지표를 최종 기준으로 설정한다.
| 통계 개념 | ML 대응 지표 | 해석 |
|---|---|---|
| \(1 - \beta\) (Power) | Recall, Sensitivity | 실제 양성을 탐지하는 능력 |
| \(\alpha\) (Type I Error Rate) | FPR, \(1 -\) Specificity | 음성을 양성으로 잘못 분류하는 비율 |
| \(\beta\) (Type II Error Rate) | FNR, \(1 -\) Recall | 양성을 음성으로 잘못 분류하는 비율 |
| \(1 - \alpha\) (Specificity) | Specificity, TNR | 실제 음성을 올바르게 분류하는 능력 |