logo

문턱값

실습 준비

import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import (
    accuracy_score,
    f1_score,
    precision_score,
    recall_score,
    roc_auc_score,
    roc_curve,
)

문턱값 threshold

  • 문턱값(threshold): 모델이 출력한 양성 확률을 양성 예측으로 바꾸는 기준
  • 이 실습에서는 확률이 문턱값보다 크면 양성, 이하면 음성으로 분류
  • 문턱값을 바꾸면 혼동 행렬의 FP, FN, TP, TN 구성이 달라짐

문턱값을 높일 때

  • 문턱값을 높이면 양성이라고 예측하기가 더 어려워짐
  • 양성 예측이 줄어들면서 양성 예측의 신뢰도, 즉 정밀도는 높아질 수 있음
  • 반대로 실제 양성 중 일부를 놓치기 쉬워져 재현도는 낮아질 수 있음

문턱값을 낮출 때

  • 문턱값을 낮추면 양성이라고 예측하기가 쉬워짐
  • 더 많은 대상을 양성으로 잡기 때문에 재현도는 높아질 수 있음
  • 그러나 위양성이 함께 늘어나면 정밀도는 낮아질 수 있음

문턱값을 바꿔가면서 지표 계산

  • 여러 문턱값을 순회하면서 정확도, 정밀도, 재현도, 특이도, F1 점수를 계산
  • np.where(y_prob > threshold, 1, 0)로 문턱값별 예측값을 새로 만듦
ths = np.linspace(0.1, 0.9, 81)
accuracy = []
precision = []
recall = []
specificity = []
f1 = []

for threshold in ths:
    y_pred = np.where(y_prob > threshold, 1, 0)
    accuracy.append(accuracy_score(y_true, y_pred))
    precision.append(precision_score(y_true, y_pred))
    recall.append(recall_score(y_true, y_pred))
    specificity.append(recall_score(y_true, y_pred, pos_label=0))
    f1.append(f1_score(y_true, y_pred))

0.1부터 0.9까지 0.01 간격의 문턱값 81개를 확인.

시각화

  • 문턱값이 높아지면 정밀도와 특이도는 높아지는 경향
  • 문턱값이 낮아지면 재현도는 높아지는 경향
  • 정확도나 F1처럼 여러 오류를 함께 반영하는 지표는 특정 구간에서 최대값을 가질 수 있음
plt.plot(ths, accuracy, label="Accuracy")
plt.plot(ths, precision, label="Precision")
plt.plot(ths, recall, label="Recall")
plt.plot(ths, specificity, label="Specificity")
plt.plot(ths, f1, label="F1 Score")
plt.xlabel("Threshold")
plt.legend()
plt.show()

문턱값에 따른 정확도, 정밀도, 재현도, 특이도와 F1 점수 변화

F1이 가장 높은 문턱값 찾기

  • np.argmax(f1)로 F1 점수가 가장 큰 위치의 인덱스를 찾음
  • 해당 인덱스로 최적 문턱값과 최대 F1 점수를 확인
  • 그래프에 빨간 점과 점선을 추가해 최고 F1 지점을 표시
best_index = np.argmax(f1)  # 가장 큰 F1 점수의 인덱스
best_threshold = ths[best_index]
best_threshold  # 최대 F1의 문턱값
실행 결과
np.float64(0.48)
best_f1 = f1[best_index]
best_f1  # 최대 F1 점수
실행 결과
0.7683049147442327

F1 점수가 가장 높은 문턱값은 0.48, 최대 F1 점수는 약 76.8%.

plt.plot(ths, f1)
plt.axvline(best_threshold, color="r", linestyle="--")
plt.plot(best_threshold, best_f1, "ro")
plt.xlabel("Threshold")
plt.ylabel("F1 Score")
plt.show()

F1 점수가 최대가 되는 문턱값 0.48을 표시한 그래프

ROC 곡선 Receiver operating characteristic Curve

  • ROC 곡선(Receiver Operating Characteristic Curve)은 신호 이론에서 유래
  • 가로축은 1 - 특이도, 즉 FPR(False Positive Rate)
  • 세로축은 재현도, 즉 TPR(True Positive Rate)
  • 문턱값을 변화시키면서 특이도와 재현도의 변화를 곡선으로 표시
  • 무작위로 예측할 경우 TPR = FPR인 대각선에 가까움
  • AUC(Area Under the Curve)는 0~1 범위이며, 클수록 높은 성능을 의미

ROC 곡선에서 무작위 예측과 성능이 높은 곡선 비교

Python ROC 곡선

  • roc_curve()로 FPR, TPR, 문턱값을 계산
  • roc_auc_score()로 ROC 곡선 아래 면적, 즉 AUC를 계산
fpr, tpr, roc_thresholds = roc_curve(y_true, y_prob)
plt.plot(fpr, tpr)
plt.plot([0, 1], [0, 1], linestyle="--")
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.show()

Fashion MNIST 이항 분류 모델의 ROC 곡선

roc_auc = roc_auc_score(y_true, y_prob)
roc_auc  # ROC AUC
실행 결과
0.8270230000000001

ROC AUC는 약 0.827.

Previous
혼동 행렬