문턱값 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 구성이 달라짐
문턱값과 정밀도
정밀도는 양성으로 예측한 것 중 실제 양성인 비율
아래 예시에서는 양성 예측 8개 중 5개가 실제 양성이므로 정밀도는 5/8
Precision = T P + F P T P
문턱값과 재현도
재현도는 실제 양성 중 모델이 양성으로 찾아낸 비율
아래 예시에서는 실제 양성 8개 중 5개를 찾아냈으므로 재현도는 5/8
Recall = T P + F N T P
문턱값을 높일 때
문턱값을 높이면 양성이라고 예측하기가 더 어려워짐
양성 예측이 줄어들면서 양성 예측의 신뢰도, 즉 정밀도는 높아질 수 있음
반대로 실제 양성 중 일부를 놓치기 쉬워져 재현도는 낮아질 수 있음
문턱값을 낮출 때
문턱값을 낮추면 양성이라고 예측하기가 쉬워짐
더 많은 대상을 양성으로 잡기 때문에 재현도는 높아질 수 있음
그러나 위양성이 함께 늘어나면 정밀도는 낮아질 수 있음
문턱값을 바꿔가면서 지표 계산
여러 문턱값을 순회하면서 정확도, 정밀도, 재현도, 특이도, 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이 가장 높은 문턱값 찾기
np.argmax(f1)로 F1 점수가 가장 큰 위치의 인덱스를 찾음
해당 인덱스로 최적 문턱값과 최대 F1 점수를 확인
그래프에 빨간 점과 점선을 추가해 최고 F1 지점을 표시
i = np.argmax(f1)
plt.plot(ths, f1)
best_threshold = ths[i]
best_f1 = f1[i]
plt.plot((best_threshold, best_threshold), (0 , best_f1), color='r' , linestyle='--' )
plt.plot(best_threshold, best_f1, 'ro' )
plt.xlabel('Threshold' )
plt.ylabel('F1 Score' )
best_threshold, best_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 범위이며, 클수록 높은 성능을 의미
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)
roc_auc_score(y_test, prob)
실습 데이터: 온라인 강의 완주 예측
classification.mdx 실습과 같은 온라인 강의 완주 데이터 사용
첫 주 학습 행동으로 최종 완주 여부 예측
completed는 0=미완주, 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 ]
위 코드를 실행한 뒤 개념 문항과 이어지는 실습 문항을 순서대로 해결하세요.