워크드 예제: 손으로 ROC와 AUC 계산하기
Contents
학습목표 — 이 장을 마치면 다음을 할 수 있다.
- 작은 데이터로 임계값을 스윕하며 TP·FP·TPR·FPR 표를 손으로 채운다.
- (FPR, TPR) 점들과 사다리꼴 적분으로 AUC를 직접 계산한다.
- 손계산 AUC = 확률 해석(쌍 세기) AUC = 그림의 AUC가 일치하는지 검증한다.
작은 데이터로 직접 손을 더럽혀 보자
지금까지 02장에서 ROC 곡선이 그려지는 원리를, 03장에서 AUC가 면적이자 확률임을 배웠다. 개념은 갖췄으니, 이제 진짜로 이해했는지는 작은 데이터로 한 칸씩 손계산해 보면 드러난다. 외운 공식이 실제 숫자로 맞아떨어지는 순간만큼 개념을 단단히 굳히는 일은 없다.
우리가 쓸 데이터는 일부러 작고 명시적이다 — 양성 5개, 음성 5개, 총 10개. 충분히 작아 손으로 끝까지 따라갈 수 있으면서도, 곡선이 완벽(AUC=1.0)이 되지 않도록 의도적으로 음성 하나를 높은 점수에 끼워 두어 현실감을 살렸다. 이 장의 목표는 같은 AUC 값(0.76)을 세 갈래 길로 — 사다리꼴 면적, 확률 쌍 세기, 그리고 그림 — 도달해 셋이 만나는 것을 두 눈으로 확인하는 것이다.
전체 절차를 한 장의 흐름도로 먼저 펼쳐 두자. 우리는 이 길을 차례로 걸어갈 것이다.
1단계 — 데이터와 정렬
먼저 데이터다. 각 사례에는 모델이 매긴 점수(0~100)와 실제 라벨(양성/음성)이 있다. 점수가 높을수록 모델이 "양성일 것 같다"고 본 것이다. 이미 점수 내림차순으로 정렬해 두었다 — ROC를 그릴 때는 점수가 높은 사례부터 양성으로 넘어오므로, 내림차순 정렬이 스윕의 출발점이다.
| # | 점수 score | 실제 라벨 |
|---|---|---|
| 1 | 95 | 양성 (1) |
| 2 | 90 | 양성 (1) |
| 3 | 80 | 음성 (0) |
| 4 | 75 | 양성 (1) |
| 5 | 65 | 음성 (0) |
| 6 | 60 | 양성 (1) |
| 7 | 50 | 음성 (0) |
| 8 | 40 | 양성 (1) |
| 9 | 30 | 음성 (0) |
| 10 | 20 | 음성 (0) |
전체 양성 수 P = 5, 전체 음성 수 N = 5다. 한 가지를 미리 눈여겨보자. 3번 사례(점수 80)는 음성인데도 양성 둘(75·60·40 중 일부)보다 높은 점수를 받았다. 이 한 줄의 "끼어든 음성"이 나중에 곡선을 좌상단 모서리에서 살짝 떼어 놓고, AUC를 1.0이 아닌 0.76으로 만드는 장본인이다.
2단계 — 임계값 스윕 표 채우기
이제 02장의 작도 원리("한 임계값 → 한 혼동행렬 → 한 점")를 그대로 실행한다. 규칙은 점수 ≥ 임계값이면 양성으로 예측. 임계값을 +∞(아무도 양성 아님)에서 시작해 데이터의 각 점수로 한 칸씩 내리며, 매 단계 TP·FP·FN·TN을 세고 TPR = TP/5, FPR = FP/5를 계산한다.
| 임계값(≥) | TP | FP | FN | TN | TPR = TP/5 | FPR = FP/5 | (FPR, TPR) |
|---|---|---|---|---|---|---|---|
| +∞ (시작) | 0 | 0 | 5 | 5 | 0.00 | 0.00 | (0.0, 0.0) |
| 95 | 1 | 0 | 4 | 5 | 0.20 | 0.00 | (0.0, 0.2) |
| 90 | 2 | 0 | 3 | 5 | 0.40 | 0.00 | (0.0, 0.4) |
| 80 | 2 | 1 | 3 | 4 | 0.40 | 0.20 | (0.2, 0.4) |
| 75 | 3 | 1 | 2 | 4 | 0.60 | 0.20 | (0.2, 0.6) |
| 65 | 3 | 2 | 2 | 3 | 0.60 | 0.40 | (0.4, 0.6) |
| 60 | 4 | 2 | 1 | 3 | 0.80 | 0.40 | (0.4, 0.8) |
| 50 | 4 | 3 | 1 | 2 | 0.80 | 0.60 | (0.6, 0.8) |
| 40 | 5 | 3 | 0 | 2 | 1.00 | 0.60 | (0.6, 1.0) |
| 30 | 5 | 4 | 0 | 1 | 1.00 | 0.80 | (0.8, 1.0) |
| 20 | 5 | 5 | 0 | 0 | 1.00 | 1.00 | (1.0, 1.0) |
표를 읽는 법을 한 줄 한 줄 따라가 보자. 처음 두 행(임계값 95, 90)에서는 양성 둘만 넘어와 TP가 0 → 1 → 2로 오르지만 FP는 0인 채다. 점이 (0,0.2) → (0,0.4)로 세로로만 올라가는 이유다(02장의 "양성을 넘기면 세로↑"). 그러다 임계값 80에서 끼어든 음성이 양성으로 넘어오며 FP가 처음으로 1이 되고, 점이 (0.2,0.4)로 오른쪽으로 꺾인다("음성을 넘기면 가로→"). 이후로도 양성이 넘어오면 위로, 음성이 넘어오면 옆으로 한 칸씩 움직이며 마지막 임계값 20에서 모두 양성이 되어 (1,1)에 도달한다.
이렇게 얻은 11개의 (FPR, TPR) 점이 ROC 곡선의 골격이다.
(0,0) · (0,0.2) · (0,0.4) · (0.2,0.4) · (0.2,0.6) · (0.4,0.6) · (0.4,0.8) · (0.6,0.8) · (0.6,1.0) · (0.8,1.0) · (1.0,1.0)
이 11개 점은 02장의 Figure이 순차로 찍던 바로 그 점들이고, 02장에서 본 세 짝 그림(임계값 85·60·30)도 이 표의 행과 정확히 맞물린다. 임계값 85는 90과 80 사이이므로 thr=90 행과 같은 (0,0.4), 임계값 60은 (0.4,0.8) 행, 임계값 30은 (0.8,1.0) 행이다. 본문 표와 그림이 1:1로 일치한다.
3단계 — 점을 찍고 곡선 그리기
이제 11개 점을 ROC 평면에 찍고 계단선으로 이으면 곡선이 완성된다.
곡선의 모양에 사연이 담겨 있다. 처음에 FPR=0인 채로 TPR이 0.4까지 곧장 올라간 것은 가장 높은 점수의 양성 둘을 거짓경보 없이 맞혔다는 뜻이다. 곡선이 좌상단 (0,1)에 완전히 닿지 못하고 (0,0.4)에서 오른쪽으로 꺾인 것은 1단계에서 점찍어 둔 그 "끼어든 음성"(점수 80) 때문이다. 이 작은 결함이 면적을 정사각형 전체(1.0)에서 깎아낸다 — 얼마나 깎였는지를 다음 단계에서 정확히 잰다.
4단계 — 사다리꼴 적분으로 AUC 계산 (검산 1)
곡선 아래 면적을 구하는 표준 방법은 사다리꼴 적분이다. 곡선을 가로 방향(FPR)으로 잘게 쪼개, 각 구간을 사다리꼴(좌·우 높이를 평균한 직사각형)로 보고 넓이를 더한다. 각 사다리꼴 넓이 = 폭 × (좌 높이 + 우 높이) / 2.
여기서 한 가지 절약이 있다. FPR이 변하지 않는 구간(점이 세로로만 움직인 구간)은 폭이 0이라 면적에 기여하지 않는다. 그러니 FPR이 증가하는 가로 구간만 따지면 된다. 우리 곡선에서 FPR은 0 → 0.2 → 0.4 → 0.6 → 0.8 → 1.0으로 폭 0.2씩 다섯 번 증가하므로, 사다리꼴 다섯 개만 계산한다.
| FPR 구간 | 폭 w | 좌 높이 TPR | 우 높이 TPR | 사다리꼴 면적 = w·(좌+우)/2 |
|---|---|---|---|---|
| 0.0 → 0.2 | 0.2 | 0.4 | 0.4 | 0.2 · 0.4 = 0.08 |
| 0.2 → 0.4 | 0.2 | 0.6 | 0.6 | 0.2 · 0.6 = 0.12 |
| 0.4 → 0.6 | 0.2 | 0.8 | 0.8 | 0.2 · 0.8 = 0.16 |
| 0.6 → 0.8 | 0.2 | 1.0 | 1.0 | 0.2 · 1.0 = 0.20 |
| 0.8 → 1.0 | 0.2 | 1.0 | 1.0 | 0.2 · 1.0 = 0.20 |
다섯 조각을 더하면,
AUC = 0.08 + 0.12 + 0.16 + 0.20 + 0.20 = 0.76.
표를 보면 각 구간의 좌·우 높이가 서로 같다(0.4와 0.4, 0.6과 0.6 …). 왜 그럴까? 우리 ROC는 "위로 한 칸 올라간 뒤 오른쪽으로 한 칸 가는" 계단형이라, FPR이 증가하는 가로 구간에 들어설 때는 TPR이 이미 그 높이로 고정돼 있기 때문이다. 그래서 사다리꼴이 사실상 직사각형이 되고, 계산이 폭 × 높이로 간단해진다. 첫 번째 길로 얻은 답은 0.76이다.
5단계 — 확률 해석으로 교차검증 (검산 2)
같은 답에 전혀 다른 길로 도달해 보자. 03장의 확률 해석 — AUC = P(무작위 양성 점수 > 무작위 음성 점수) — 을 손으로 세는 것이다. 양성 점수는 {95, 90, 75, 60, 40}, 음성 점수는 {80, 65, 50, 30, 20}. 양성 하나와 음성 하나로 만들 수 있는 쌍은 5 × 5 = 25쌍이고, 그중 양성이 더 높은 쌍을 센다(이 데이터엔 동점이 없다).
| 양성↓ \ 음성→ | 80 | 65 | 50 | 30 | 20 | 이긴 수 |
|---|---|---|---|---|---|---|
| 95 | ✓ | ✓ | ✓ | ✓ | ✓ | 5 |
| 90 | ✓ | ✓ | ✓ | ✓ | ✓ | 5 |
| 75 | ✗ | ✓ | ✓ | ✓ | ✓ | 4 |
| 60 | ✗ | ✗ | ✓ | ✓ | ✓ | 3 |
| 40 | ✗ | ✗ | ✗ | ✓ | ✓ | 2 |
각 행에서 양성이 이긴 횟수를 더하면 5 + 5 + 4 + 3 + 2 = 19. 따라서 확률은,
AUC = 19 / 25 = 0.76.
표에서 ✗가 찍힌 칸들을 보면 흥미롭다. 양성 75·60·40이 음성 80에게 진 것(✗)은, 바로 1단계의 그 "끼어든 음성"(점수 80)이 세 양성보다 높은 점수를 받았기 때문이다. 곡선을 좌상단에서 떼어 놓은 그 한 줄이, 여기서는 진 쌍 6개로 정확히 모습을 드러낸다. 면적이 깎인 양과 진 쌍의 수가 같은 원인에서 나온 것이다.
6단계 — 세 길의 일치 확인
두 갈래 길로 손계산한 결과를 나란히 놓아 보자.
- 검산 1 (사다리꼴 면적): 0.08 + 0.12 + 0.16 + 0.20 + 0.20 = 0.76
- 검산 2 (확률 쌍 세기): 19 / 25 = 0.76
- 그림 (Figure 1)·표준 라이브러리(
roc_auc_score): 0.76
세 길이 모두 0.76에서 만난다. 이것은 우연이 아니라 03장에서 본 정리의 구체적 확인이다 — 곡선 아래 면적과 "양성이 음성보다 높을 확률"은 같은 값(Mann–Whitney U)이기 때문이다. 그림이 그리는 면적, 손으로 적분한 면적, 쌍을 세어 얻은 확률이 한 숫자로 수렴하는 이 순간이, ROC와 AUC가 서로 다른 정의가 아니라 한 개념의 여러 얼굴임을 가장 분명하게 보여 준다.
여기까지 따라왔다면 당신은 이제 ROC 곡선을 손으로 그리고 AUC를 손으로 계산해 검산까지 할 수 있다. 남은 챕터들은 이 토대 위에서 실전의 문제들 — 어떤 임계값을 운영점으로 고를지(05), 불균형 데이터에서 ROC가 왜 낙관적인지(06), 다중분류는 어떻게 다루는지(07), 흔한 오해는 무엇인지(08) — 로 나아간다.
정리
- 표준 예제데이터(양성 5·음성 5)에서 임계값을 +∞부터 20까지 스윕해 TP·FP·FN·TN 표를 채우면 (FPR, TPR) 점 11개가 나온다.
- 점을 이으면 계단형 ROC 곡선이 되고, "끼어든 음성"(점수 80) 때문에 곡선이 좌상단에 완전히 닿지 못한다.
- 사다리꼴 적분: 0.08 + 0.12 + 0.16 + 0.20 + 0.20 = AUC 0.76.
- 확률 쌍 세기: 25쌍 중 양성이 이긴 19쌍 → 19/25 = 0.76.
- 세 길(면적·확률·그림/라이브러리)이 모두 0.76으로 일치 — AUC가 한 개념의 여러 얼굴임을 손으로 검증했다.