RyanNerd
라덕'Story
RyanNerd
  • 분류 전체보기 (60) N
    • Study Note (25) N
      • Python (3)
      • R (1)
      • Airflow (7)
      • 통계 (14) N
    • 빅데이터분석기사 (1)
      • 필기 (1)
    • Programmers (28)
      • Python (13)
      • SQL (15)
    • Project (3)
      • Django (3)
    • Mac (2)
    • 맛집 (0)

블로그 메뉴

  • NaverBlog
  • 홈

최근 글

전체 방문자
오늘
어제
hELLO · Designed By 정상우.
RyanNerd

라덕'Story

Study Note/통계

정확도(Accuracy)의 함정: 민감도, 특이도, 그리고 베이즈 정리

2025. 12. 17. 13:41

의료 데이터 분석가로서 분류 모델(로지스틱 회귀 등)을 만들었을 때, 가장 먼저 듣게 되는 질문은 "정확도가 몇 %인가?"입니다. 하지만 의료 데이터, 특히 희귀 질환(Imbalanced Data)을 다룰 때 정확도는 가장 위험한 지표가 될 수 있습니다.

 

오늘은 혼동행렬(Confusion Matrix)을 해부하고, 의료 현장에서 진짜 중요한 지표인 민감도, 특이도, 그리고 ROC 곡선을 정리해보겠습니다. 또한, 베이즈 정리를 통해 "AI가 양성이라고 했을 때 진짜 양성일 확률"을 계산하는 법을 알아봅니다.

 

1. 혼동행렬 (Confusion Matrix): 4가지 경우의 수

모델의 예측 결과는 딱 4가지로 나뉩니다. (암 환자 예측 예시)

구분 실체 환자(Disease,1) 실제 정상(Normal,0)
예측 환자(Positive,1) TP(True Positive) FP(False Positive)
질병을 잘 맞춤 정상인데 질병이 있다고 오진
예측 정상(Negative,0) FN(False Negative) TN(True Negative)
질병인데 정상이라 진단 정상을 정상이라 잘 맞춤

 

2. 의료 핵심 지표 3대장 (민감도, 특이도, 정밀도)

정확도(Accuracy)는 $(TP+TN) / 전체$ 입니다. 하지만 암 환자가 100명 중 3명뿐이라면, 무조건 "정상"이라고 찍어도 정확도는 97%가 나옵니다. (정확도의 맹점)

그래서 다음 지표들을 봐야 합니다.

① 민감도 (Sensitivity = Recall)

  • 정의: 실제 환자($P$) 중에 모델이 아프다고 찾아낸 비율. ($TP / (TP+FN)$)
  • 의료적 의미: "놓치지 않을 확률". 암 검진(Screening)처럼 병을 발견하는 게 최우선일 때 가장 중요합니다.

② 특이도 (Specificity)

  • 정의: 실제 정상인($N$) 중에 모델이 정상이라고 분류한 비율. ($TN / (TN+FP)$)
  • 의료적 의미: "건강한 사람을 겁주지 않을 확률". 특이도가 낮으면 멀쩡한 사람이 재검사를 받아야 하므로 비용과 불안이 증가합니다.

③ 정밀도 (Precision = PPV)

  • 정의: 모델이 "환자"라고 예측한 사람 중에 진짜 환자의 비율. ($TP / (TP+FP)$)
  • 의료적 의미: "AI의 진단 신뢰도". 수술이나 독한 항암제처럼 리스크가 큰 처방을 내릴 때는 정밀도가 높아야 합니다.
  •  

3. ROC 곡선과 AUC: 컷오프(Cut-off) 전쟁

로지스틱 회귀는 0~1 사이의 확률을 뱉습니다. 보통 0.5를 기준으로 자르지만, 의료에서는 상황에 따라 이 기준(Threshold)을 바꿉니다.

  • 기준 확률을 낮추면 (예: 0.1): 조금만 의심돼도 환자라고 함 $\rightarrow$ 민감도 증가, 특이도 감소. (놓치면 안 될 때)
  • 기준 확률을 높이면 (예: 0.9): 확실할 때만 환자라고 함 $\rightarrow$ 특이도/정밀도 증가, 민감도 감소. (확진이 필요할 때)
  • ROC 곡선: 이 모든 기준값에 따른 민감도 vs 1-특이도를 그린 곡선입니다.
  • AUC (Area Under Curve): 곡선 아래 면적. 1에 가까울수록 완벽한 모델이고, 0.5면 찍는 수준입니다.

 

4.  베이즈 정리와 AI의 "진짜" 신뢰도

 "기저율의 오류(Base Rate Fallacy)"

시나리오

  • 전체 500명 중 환자는 30명 (유병률 6%, $P(D)=0.06$).
  • AI 모델 성능: 민감도 92%, 특이도 90% (꽤 훌륭해 보임).
  • 질문: 이 AI가 "환자입니다(Positive)"라고 했을 때, 진짜 환자일 확률($P(Real|Pred)$)은?

계산 (베이즈 정리)

$$P(\text{Real}|\text{Pred}) = \frac{P(\text{Pred}|\text{Real})P(\text{Real})}{P(\text{Pred})}$$
  • $TP$ (진짜 환자를 맞춤): $30명 \times 0.92 = 27.6명$
  • $FP$ (정상을 환자로 오진): $470명 \times (1-0.90) = 47명$
  • 결과: $\frac{27.6}{27.6 + 47} \approx 0.37$ (37%)

충격적인 결론

민감도가 92%인 우수한 모델이라도, 질병 자체가 희귀하면 "양성 판정"을 받았을 때 진짜 환자일 확률은 37%밖에 안 됩니다. (나머지 63%는 오진!)

$\rightarrow$ 이것이 바로 의사가 AI 결과를 맹신하면 안 되고, 확진 검사(Biopsy 등)가 필요한 이유입니다.

 

5.  Python & R 코드

유방암 데이터셋을 사용하여 모델을 평가해 봅니다.

Python (sklearn)

import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score, precision_score, recall_score, roc_auc_score

# 1. 데이터 로드 (유방암 데이터: 0=Malignant(악성), 1=Benign(양성))
# 편의상 악성을 1로 두기 위해 target을 뒤집는 경우도 있지만 여기선 그대로 씁니다.
data = load_breast_cancer()
X = data.data
y = data.target 

# 2. 분할 및 학습
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
model = LogisticRegression(max_iter=10000)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1] # 확률값

# 3. 혼동행렬 및 지표 출력
cm = confusion_matrix(y_test, y_pred)
print("=== Confusion Matrix ===")
print(cm)
print(f"Accuracy (정확도): {accuracy_score(y_test, y_pred):.4f}")
print(f"Sensitivity (Recall, 민감도): {recall_score(y_test, y_pred):.4f}")
print(f"Precision (정밀도): {precision_score(y_test, y_pred):.4f}")
print(f"AUC Score: {roc_auc_score(y_test, y_prob):.4f}")

 

R Code (caret, pROC)

# install.packages("caret")
# install.packages("pROC")
# install.packages("mlbench") # 데이터용
library(caret)
library(pROC)
library(mlbench)

# 1. 데이터 로드 (BreastCancer)
data(BreastCancer)
df <- na.omit(BreastCancer) # 결측치 제거
df$Class <- ifelse(df$Class == "malignant", 1, 0) # 1: 악성, 0: 양성

# 2. 데이터 분할
set.seed(42)
index <- createDataPartition(df$Class, p=0.7, list=FALSE)
train <- df[index, ]
test <- df[-index, ]

# 3. 모델 학습
model <- glm(Class ~ Cl.thickness + Cell.size + Cell.shape, data=train, family=binomial)

# 4. 예측 (확률 -> 0.5 기준 절단)
prob <- predict(model, newdata=test, type="response")
pred_class <- ifelse(prob > 0.5, 1, 0)

# 5. 혼동행렬 및 지표 (caret 패키지의 confusionMatrix가 매우 강력함)
# positive='1' 옵션으로 무엇이 '양성'인지 지정해야 함
confusionMatrix(factor(pred_class), factor(test$Class), positive="1")

# 6. ROC 및 AUC
roc_obj <- roc(test$Class, prob)
plot(roc_obj, print.auc=TRUE, main="ROC Curve")

 

모델을 만들었다면 이제 결과를 확인해볼 시간입니다.

의료 데이터, 특히 암 진단 모델에서 가장 중요한 것은 "암 환자를 놓치지 않는 것(Sensitivity)"입니다.

Confusion Matrix와 ROC Curve를 통해 모델을 분석해 보겠습니다.

 

1. 혼동행렬 (Confusion Matrix) 상세 분석

모델이 예측한 결과와 실제 정답을 비교한 표입니다.

 

결과 뜯어보기 (총 204명 데이터)

  1. TN (True Negative, 126명):
    • 실제 정상인데, 모델도 "정상입니다"라고 완벽하게 맞춤.
  2. TP (True Positive, 68명):
    • 실제 암 환자인데, 모델이 "암입니다"라고 정확하게 찾아냄.
  3. FP (False Positive, 8명) :
    • 실제는 정상인데, 모델이 "암일 수도 있습니다"라고 과잉 진단함.
    • 의료적 영향: 환자가 놀라서 재검사를 받아야 하지만, 생명에 지장은 없음.
  4. FN (False Negative, 2명) - ( 가장 중요):
    • 실제는 암 환자인데, 모델이 "정상입니다"라고 놓침.
    • 의료적 영향: 치료 시기를 놓칠 수 있어 가장 치명적인 오류임. 이 숫자가 2명으로 매우 적다는 것이 이 모델의 핵심 강점입니다.

2. 핵심 성능 지표 (Key Metrics)

의료 현장에서 중요하게 보는 지표들을 계산해 보았습니다.

 

지표 값 해석
정확도 (Accuracy) 95.1% 전체 환자 중 95%를 올바르게 진단했습니다. 매우 우수한 성적입니다.
민감도 (Sensitivity) 97.14% 가장 중요한 지표. 실제 환자 70명 중 68명을 찾아냈습니다. (놓칠 확률이 3% 미만)
특이도 (Specificity) 94.03% 정상인 사람을 정상이라고 판별하는 능력도 94%로 높습니다.
정밀도 (Pos Pred Value) 89.47% 모델이 "질병입니다"라고 했을 때, 실제 질병일 확률은 약 89.5%입니다.

 

Analyst Note: 질병진단(Screening) 모델에서는 민감도(Sensitivity)가 생명입니다. 이 모델은 97.14%의 높은 민감도를 기록했으므로, 1차 스크리닝 도구로 활용하기에 아주 적합합니다.

 

2. ROC Curve 및 AUC 분석

 

그래프가 왼쪽 위 모서리(Top-Left)에 아주 바짝 붙어 있는 것을 볼 수 있습니다. 이는 모델 성능이 매우 좋다는 시각적 증거입니다.

  • AUC (Area Under Curve): 0.977
    • ROC 곡선 아래의 면적이 0.977입니다. (만점은 1.0)
    • 해석: 이 모델은 무작위로 환자와 정상인을 뽑았을 때, 환자를 더 높은 위험도로 평가할 확률이 97.7%나 된다는 뜻입니다.
    • 통계적으로 "Excellent(탁월함)" 등급에 해당합니다.

요약

  1. 정확도의 함정: 희귀 질환에서는 정확도가 높아도 환자를 다 놓칠 수 있다.
  2. 민감도(Recall): 환자를 놓치지 않는 능력 (Screening용).
  3. 특이도(Specificity): 정상인을 정상으로 보는 능력.
  4. ROC/AUC: 기준값(Threshold) 변화에 따른 모델의 전체적인 성능 성적표.
  5. 베이즈 정리: 유병률이 낮으면, AI가 "양성"이라 해도 진짜 양성일 확률은 낮을 수 있다. (확진 검사 필수)

 

 

'Study Note > 통계' 카테고리의 다른 글

분류 문제의 시작, 로지스틱 회귀(Logistic Regression) 완벽 해부  (0) 2025.12.16
숫자를 센다? 무조건 '푸아송 회귀'입니다. (feat. 의료 데이터 활용법)  (0) 2025.12.15
직선을 넘어 곡선으로, 그리고 모델의 성적표 AIC  (0) 2025.12.15
회귀분석의 확장: 과적합 방지와 데이터 특성에 맞는 모델링  (0) 2025.12.15
회귀모형의 진단: 잔차, 레버리지, 그리고 쿡의 거리  (0) 2025.12.15
    'Study Note/통계' 카테고리의 다른 글
    • 분류 문제의 시작, 로지스틱 회귀(Logistic Regression) 완벽 해부
    • 숫자를 센다? 무조건 '푸아송 회귀'입니다. (feat. 의료 데이터 활용법)
    • 직선을 넘어 곡선으로, 그리고 모델의 성적표 AIC
    • 회귀분석의 확장: 과적합 방지와 데이터 특성에 맞는 모델링
    RyanNerd
    RyanNerd
    라이언 덕후의 일상 스토리~

    티스토리툴바