로지스틱 회귀 평가: 정확도·ROC 곡선·AUC 해석과 임계값 운영
로지스틱 회귀의 정확도, ROC 곡선, AUC를 비교하고 비용·제약 조건에 맞춘 임계값 선택과 검증 방법을 정리한다.
2026-08-14 · 최초 발행 2024-04-29
확률 출력과 평가 지표가 만나는 지점
로지스틱 회귀는 이진 분류에서 p(y=1|x) 형태의 확률값을 낸다. 이 값을 임계값 τ와 비교해 ŷ = 1[p ≥ τ]로 예측 라벨을 정한다. 따라서 모델 평가에는 확률의 순위화 품질과 특정 임계값에서의 분류 결과를 구분하는 관점이 필요하다.
정확도는 전체 표본 가운데 정답 비율을 나타내는 혼동 행렬 기반 지표다. ROC 곡선은 모든 임계값에서 FPR과 TPR이 어떻게 변하는지 보여 주며, AUC는 그 곡선 아래 면적으로 순위화 성능을 요약한다.
AUC는 0.5~1.0 범위로 해석할 수 있다. 무작위로 뽑은 양성·음성 표본 쌍에서 양성에 더 높은 점수를 부여할 확률이라는 관점도 가능하다.
정확도만으로 모델을 고르기 어려운 이유
정확도는 직관적이고 비교하기 쉽지만, 선택한 임계값에 따라 값이 바뀐다. 클래스 비율이 치우친 상황에서는 특히 주의가 필요하다. 예를 들어 음성이 99%인 데이터에서 모든 표본을 음성으로 예측해도 정확도는 99%가 된다.
이 때문에 정확도는 균형 데이터에서 간단한 기준으로 활용할 수 있으나, 모델 선택의 유일한 지표로 쓰기에는 한계가 있다. 임계값 독립 지표와 함께 보조적으로 보는 편이 적절하다.
ROC 곡선이 보여 주는 운영점의 범위
ROC 곡선의 좌표는 다음과 같다.
FPR = FP/(FP+TN)TPR = TP/(TP+FN)
임계값을 바꾸면 TPR과 FPR도 함께 변한다. ROC 곡선은 이 교환관계를 전체 임계값 범위에서 드러내므로, 단일 정확도 값만으로는 보이지 않는 운영 후보 지점을 비교할 수 있게 한다.
ROC는 클래스 비율 변화에 상대적으로 둔감하지만, 실제 운영점은 비용 구조와 서비스·규제 제약까지 반영해서 정해야 한다.
AUC는 후보 압축에 쓰고, 임계값은 별도로 정한다
AUC가 0.5이면 무작위 수준이고 1.0이면 완벽하게 분리한 상태다. 표본 크기가 충분할 때 모델 간 순위화 품질을 비교하는 데 유용하며, 후보 모델을 선별하는 첫 단계에 잘 맞는다.
다만 AUC는 특정 임계값을 전제로 하지 않는다. 특정 FPR 또는 TPR 제약을 만족해야 하는 운영 환경에서는 AUC가 높더라도 실제 운영 성능과 차이가 날 수 있다. 후보 선별과 운영 임계값 결정을 분리해야 하는 이유다.
비용과 제약을 반영해 임계값을 고르는 방법
비용을 기준으로 임계값 τ를 선택할 때 기대 비용은 다음처럼 표현할 수 있다.
E[cost(τ)] = c_fp·FPR(τ)·(1−π) + c_fn·(1−TPR(τ))·π
여기서 π는 양성 비율이다. 정상 차단과 양성 미검출의 비용이 다르면, 정확도가 가장 높은 지점보다 기대 비용이 가장 낮은 지점이 더 적절한 운영점일 수 있다.
진단 목적에서는 Youden’s J = TPR − FPR를 최대화하는 방식으로 τ를 고를 수 있다. 반대로 TPR ≥ α 또는 FPR ≤ β처럼 제약이 주어진 경우에는 그 범위 안에서 비용이 최소가 되는 임계값을 탐색한다.
검증 과정에서 확인할 항목
층화 교차검증(Stratified k-fold)은 AUC와 정확도의 평균·분산을 추정하는 데 사용한다. AUC 신뢰구간은 부트스트랩 또는 DeLong 방법으로 다룰 수 있다.
전처리와 보정 절차는 데이터 누수와 직접 연결된다. 스케일링, 특징 선택, 보정은 반드시 각 Fold 내부에서 적합하고 적용해야 한다.
| 지표 | 임계값 의존성 | 불균형 민감도 | 해석 용이성 | 최적화 대상 | 권장 사용 맥락 |
|---|---|---|---|---|---|
| 정확도 | 높음 | 높음 | 매우 높음 | 라벨 일치율 | 균형 데이터, 간단 기준 |
| ROC 곡선 | 낮음 | 낮음 | 중간 | TPR-FPR 곡선 | 운영점 탐색, 모델 스크리닝 |
| AUC | 낮음 | 낮음 | 높음 | 순위화 품질 | 모델 비교·선정 1차 필터 |
목적에 따라 달라지는 평가 기준
의료 이진 진단에서는 TPR ≥ 0.95를 보장하면서 허용 가능한 FPR을 최소화하는 지점이 목적이 될 수 있다. ROC에서 TPR 0.95를 만족하는 최소 FPR 지점의 τ를 선택하고, AUC로 후보를 걸러낸 뒤 교차검증으로 분산을 확인한다.
금융 사기 탐지는 기대 손실 최소화가 중심이다. 정상 차단 비용을 c_fp, 사기 미검출 비용을 c_fn으로 둔 비용 행렬을 설정한 뒤 비용 기반으로 τ를 탐색한다. ROC-AUC는 후보 선정에 쓰고, 운영점은 비용 기준으로 확정한다.
마케팅 전환 예측에서는 캠페인 ROI를 목표로 예상 이익과 비용에 맞춰 임계값을 정한다. 이 경우 정확도보다 이익 기반 메트릭을 최적화하고, 캘리브레이션으로 출력 확률의 신뢰성을 확보하는 흐름이 맞는다.
실행 가능한 평가 코드
전제조건: Python 3.10+, scikit-learn ≥ 1.2, numpy, matplotlib 설치
# pip install scikit-learn numpy matplotlib
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, roc_curve, auc, confusion_matrix
from sklearn.model_selection import StratifiedKFold
from sklearn.calibration import CalibrationDisplay
RANDOM_STATE = 42
# 1) 데이터 생성(불균형 예시)
X, y = make_classification(n_samples=8000, n_features=20, n_informative=6,
n_redundant=2, weights=[0.9, 0.1], flip_y=0.01,
random_state=RANDOM_STATE)
# 2) 홀드아웃 분할
from sklearn.model_selection import train_test_split
X_tr, X_te, y_tr, y_te = train_test_split(
X, y, test_size=0.3, stratify=y, random_state=RANDOM_STATE
)
# 3) 로지스틱 회귀 학습
clf = LogisticRegression(max_iter=200, n_jobs=-1, class_weight=None, random_state=RANDOM_STATE)
clf.fit(X_tr, y_tr)
# 4) 확률 예측 및 정확도(τ=0.5)
p_te = clf.predict_proba(X_te)[:, 1]
tau = 0.5
y_pred = (p_te >= tau).astype(int)
acc = accuracy_score(y_te, y_pred)
cm = confusion_matrix(y_te, y_pred)
print(f"Accuracy(τ=0.5): {acc:.4f}")
print("Confusion matrix:\n", cm)
# 5) ROC 곡선, AUC
if len(np.unique(y_te)) < 2:
raise ValueError("Test set has a single class; ROC/AUC 불가. 분할 또는 표본 재조정 필요.")
fpr, tpr, thresholds = roc_curve(y_te, p_te)
roc_auc = auc(fpr, tpr)
print(f"ROC-AUC: {roc_auc:.4f}")
# 6) Youden's J로 τ 선택
youden = tpr - fpr
best_idx = np.argmax(youden)
best_tau = thresholds[best_idx]
print(f"Best τ (Youden J): {best_tau:.4f}, TPR={tpr[best_idx]:.3f}, FPR={fpr[best_idx]:.3f}")
# 7) 비용 기반 τ 탐색(예시 비용)
pi = y_te.mean()
c_fp, c_fn = 1.0, 10.0
cost = c_fp * fpr * (1 - pi) + c_fn * (1 - tpr) * pi
cost_idx = np.argmin(cost)
cost_tau = thresholds[cost_idx]
print(f"Cost-min τ: {cost_tau:.4f}, Expected cost={cost[cost_idx]:.6f}")
# 8) 시각화
fig, ax = plt.subplots(1, 2, figsize=(10,4))
ax[0].plot(fpr, tpr, label=f'ROC (AUC={roc_auc:.3f})')
ax[0].plot([0,1],[0,1],'k--',alpha=0.4)
ax[0].scatter(fpr[best_idx], tpr[best_idx], c='r', label='Youden J best')
ax[0].scatter(fpr[cost_idx], tpr[cost_idx], c='g', label='Cost-min')
ax[0].set_xlabel('FPR'); ax[0].set_ylabel('TPR'); ax[0].legend(); ax[0].set_title('ROC')
CalibrationDisplay.from_estimator(clf, X_te, y_te, n_bins=10, ax=ax[1])
ax[1].set_title('Calibration (Reliability)')
plt.tight_layout()
plt.show()
# 9) Stratified K-Fold ROC-AUC 교차검증
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=RANDOM_STATE)
aucs = []
for tr_idx, va_idx in cv.split(X, y):
clf_cv = LogisticRegression(max_iter=200, n_jobs=-1, random_state=RANDOM_STATE)
clf_cv.fit(X[tr_idx], y[tr_idx])
p_va = clf_cv.predict_proba(X[va_idx])[:, 1]
fpr_va, tpr_va, _ = roc_curve(y[va_idx], p_va)
aucs.append(auc(fpr_va, tpr_va))
print(f"CV ROC-AUC: mean={np.mean(aucs):.4f}, std={np.std(aucs):.4f}")
클래스 불균형에는 class_weight="balanced" 또는 표본 재가중·리샘플링을 적용할 수 있으며, ROC-AUC와 함께 PR-AUC도 점검한다. 확률 보정에는 Platt scaling(Logistic)과 Isotonic 회귀를 사용할 수 있고, 이 적합 역시 교차검증 내부에서 이뤄져야 한다.
정확도와 ROC-AUC를 함께 보고하면 임계값 의존 지표와 독립 지표를 분리해 의사결정 과정을 설명할 수 있다. AUC로 후보를 압축한 뒤 비용·제약·Youden J에 따라 운영 임계값을 선택하고, 교차검증과 CI로 성능 변동성을 확인하는 흐름이 로지스틱 분류 모델 평가의 기본 골격이 된다.