logo

문턱값

문턱값 0.5 기준 예측 코드

  • predict_proba()로 각 표본이 양성(1)일 확률을 구함
  • 기본 문턱값을 0.5로 두고, 확률이 문턱값 이상이면 양성으로 예측
  • 이렇게 만든 예측값으로 혼동 행렬을 계산
prob = model.predict_proba(X_test)[:, 1]

threshold = 0.5
y_pred_05 = (prob >= threshold).astype(int)

confusion_matrix(y_test, y_pred_05)

문턱값 threshold

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

문턱값 0.5 기준 혼동 행렬 예시

문턱값과 정밀도

  • 정밀도는 양성으로 예측한 것 중 실제 양성인 비율
  • 아래 예시에서는 양성 예측 8개 중 5개가 실제 양성이므로 정밀도는 5/8

문턱값 기준 정밀도 5/8 예시

문턱값과 재현도

  • 재현도는 실제 양성 중 모델이 양성으로 찾아낸 비율
  • 아래 예시에서는 실제 양성 8개 중 5개를 찾아냈으므로 재현도는 5/8

문턱값 기준 재현도 5/8 예시

문턱값을 높일 때

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

문턱값을 높이면 정밀도가 높아지는 예시

문턱값을 높이면 재현도가 낮아지는 예시

문턱값을 낮출 때

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

문턱값을 낮추면 정밀도가 낮아지는 예시

문턱값을 낮추면 재현도가 높아지는 예시

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

  • 여러 문턱값을 순회하면서 정확도, 정밀도, 재현도, 특이도, F1 점수를 계산
  • np.where(prob > threshold, 1, 0)로 문턱값별 예측값을 새로 만듦
import numpy as np

ths = np.arange(0.1, 0.9, 0.01)
accuracy, precision, recall, specificity, f1 = [], [], [], [], []

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

문턱값별 지표 시각화

  • 문턱값이 높아지면 정밀도와 특이도는 높아지는 경향
  • 문턱값이 낮아지면 재현도는 높아지는 경향
  • 정확도나 F1처럼 여러 오류를 함께 반영하는 지표는 특정 구간에서 최대값을 가질 수 있음
import matplotlib.pyplot as plt

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()

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

F1이 가장 높은 문턱값 찾기

  • np.argmax(f1)로 F1 점수가 가장 큰 위치의 인덱스를 찾음
  • 해당 인덱스로 최적 문턱값과 최대 F1 점수를 확인
  • 그래프에 빨간 점과 점선을 추가해 최고 F1 지점을 표시
i = np.argmax(f1)  # 가장 큰 F1 점수의 인덱스
plt.plot(ths, f1)

best_threshold = ths[i]  # 가장 큰 F1 점수의 임계값
best_f1 = f1[i]          # 가장 큰 F1 점수

plt.plot((best_threshold, best_threshold), (0, best_f1), color='r', linestyle='--')
plt.plot(best_threshold, best_f1, 'ro')  # 가장 큰 F1 점수 지점 표시
plt.xlabel('Threshold')
plt.ylabel('F1 Score')

best_threshold, best_f1

F1 점수가 가장 높은 문턱값

ROC 곡선

  • 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를 계산
# 임포트
from sklearn.metrics import roc_auc_score, roc_curve

# 시각화
fpr, tpr, threshold = roc_curve(y_test, prob)
plt.plot(fpr, tpr)

# AUC
roc_auc_score(y_test, prob)

Python으로 그린 ROC 곡선

실습 데이터: 온라인 강의 완주 예측

  • classification.mdx 실습과 같은 온라인 강의 완주 데이터 사용
  • 첫 주 학습 행동으로 최종 완주 여부 예측
  • completed0=미완주, 1=완주
  • 완주(1)를 양성 클래스로 설정

데이터 불러오기와 모델 준비

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

df_course = pd.read_excel("online_course_completion.xlsx")

X = df_course.drop(columns="completed")
y = df_course["completed"]

X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.2,
    random_state=42,
    stratify=y
)

lr = LogisticRegression(max_iter=1000)
lr.fit(X_train, y_train)
prob = lr.predict_proba(X_test)[:, 1]
  • 위 코드를 실행한 뒤 개념 문항과 이어지는 실습 문항을 순서대로 해결하세요.