분류를 하는 모델에서의 모델의 성능을 평가하는 방법을 소개합니다.
혼동행렬 Confusion Matrix
분류작업에서 사용하며, Matrix로 그려볼 수 있음.
ex) 스팸메일 100개 중 실제 스팸메일이 60개인 상황에서, 어떠한 모델의 스팸분류결과 스팸메일:80개가 나왔고 , 그중 55개가 진짜 스팸메일인 경우
이를 표로 나타내면

위와 같은 혼동행렬을 얻을 수 있다.

여기서 중요한 개념이 등장하는데 TP, FP, FN, TN 이다.
- TP ( True Positive ) : (모델이) 양성판단했는데, 실제로도 양성인경우 -> 양성판단으로 맞은경우
- TN ( True Negative ) : (모델이) 음성판단했는데, 실제로도 음성인경우 -> 음성판단으로 맞은경우
- FP ( Flase Positive ) : (모델이) 양성판단했는데, 실제로는 음성인경우 (틀린경우) -> 양성판단으로 틀린경우
- FN ( Flase Negative ) : (모델이) 음성판단했는데, 실제로는 양성인경우 (틀린경우) -> 음성판단으로 틀린경우
Precision (정밀도)
$$ TP \over {TP + FP}$$
양성 예측이 정답을 정확히 예측한 비율
분류결과 스팸메일(양성판단)로 나온 80개 중 실제 스팸메일피 55개 이므로 위의 경우 정밀도는 $5 \over {55+25} $ 이다.
Recall (재현률)
$$ TP \over {TP + FN}$$
실제로 양성인녀석들 중 모델에서 양성으로 판단한 비율
실제 스팸메일(양성) 60개 중 스팸메일로 분류(양성판단)을 받은 55개에 해당하므로 재현률은 $ 55 \over {55+5}$ 이다.
Accuracy (정확도)
$$ {TP + TN}\over{TP+TN+FP+FN}$$
전체 중 (양성 판단이든 음성 판단이든)맞은 비율
전체 메일 100개 중 스팸으로 맞게 분류된 55개의 스팸메일 , 일반메일로 맞게 분류된 15개의 일반메일 : $ {55+15}\over{100}$
F1 Score
정밀도와 재현률의 상충관계를 평가에 반영하여 조화평균한 점수이다.
대부분의 분류문제에서 데이터의 분포에 차이가 있는 경우가 많으므로 주로 F1 Score를 사용하는 경우가 많다.
만약 잘못 판정해서는 안되는 문제에서 예를들면, '정밀도 0.9 미만의 모델은 채용하지 않는다'라는 최소 조건을 정하고, 이 조건을 만족하면서 F1 Score가 높아지도록 파라미터를 튜닝한 다음 모델을 선택하면 된다.
AUC , ROC
ROC (Receiver Operating Characteristic : 수신자 조작 특성) : 모든 임계값에서 분류 모델의 성능을 보여주는 그래프
AUC (Area Under the Curve) : ROC 곡선 아래의 영역
AUC가 높다는 것은 클래스를 구벼라는 모델의 성능이 훌륭하다는 것을 의미한다.


Sensitivity 민감도 : 기존의 Precision과 같다. 실제 스팸일때, 모델결과도 스팸인경우
Specificity 특이도 : 실제 스팸이 아닐때, 모델결과도 스팸이 아니라고 나오는경우
Positive Likelihood ratio : 양성우도비 : 실제 스팸일때, 모델결과 스팸일 확률과, 실제 스팸이아닐때(일반), 모델결과가 스팸일 확률 사이의 비율
$$ {{ {True Positive Rate}\over {False Positive Rate} } }= {{Sensitivity}\over{1-Specificity}}$$
Negative Likelihood ratio : 음성우도비 : 실제 스팸일때 모델결과 일반메일일 확률과 실제 일반메일이 모델결과도 일반일 확률의 비율
$$ {{ {False Negative Rate}\over {True Negative Rate} } }= {{1-Sensitivity}\over{Specificity}}$$
Positive Predictive Value : 양성예측도 : 모델결과 스팸판정일때, 진짜로 스팸이었을 확률
Negative Predictive Value : 음성예측도 : 모델결과 일반판정일 때, 실제로 일반메일일 확률
___
from sklearn.metrics import roc_curve
from sklearn.metrics import roc_auc_score
# roc_curve(타겟값, prob of 1)
# fpr, tpr, thresholds = roc_curve(y_val, y_pred_proba)
base_prob=[0 for i in range(len(y_val))]
logit_prob[:,1]
grid_best_pipe_prob[:,1]
rand_best_pipe_prob[:,1]
# AUC
base_auc = roc_auc_score(y_val,base_prob)
logit_auc = roc_auc_score(y_val, logit_prob[:,1])
grid_auc = roc_auc_score(y_val, grid_best_pipe_prob[:,1])
rand_auc = roc_auc_score(y_val, rand_best_pipe_prob[:,1])
#Curve
base_fpr, base_tpr, _ = roc_curve(y_val,base_prob)
logit_fpr, logit_tpr, _ = roc_curve(y_val, logit_prob[:,1])
grid_fpr, grid_tpr, _ = roc_curve(y_val, grid_best_pipe_prob[:,1])
rand_fpr, rand_tpr, thresholds = roc_curve(y_val, rand_best_pipe_prob[:,1])
plt.figure(figsize=(8,8))
plt.plot(base_fpr, base_tpr, linestyle='-', label='Baseline')
plt.plot(logit_fpr, logit_tpr, marker='.', label='Logistic')
plt.plot(grid_fpr, grid_tpr, marker='.', label='GridSearchCV _ Best')
plt.plot(rand_fpr, rand_tpr, marker='.', label='RandomSearchCV _ Best')
plt.legend();plt.grid();plt.xlabel('FPR');plt.ylabel('TPR');plt.show()

아주 미세하게 RandomSearchCV_Best가 좀 더 큰값을 갖고있음을 알 수 있으며, 이는 더욱 높은 성능을 보인다고 할 수 있다.
Thresholds
넘파이의 argmax함수를 이용하면 최대값의 인덱스를 뽑을 수 있다. 여기서 fpr - tpr 를 최대로 하는 것을 찾으면
# threshold 최대값의 인덱스, np.argmax()
optimal_idx = np.argmax(rand_tpr - rand_fpr)
optimal_threshold = thresholds[optimal_idx]
print('idx:', optimal_idx, ', threshold:', optimal_threshold)
#idx: 512 , threshold: 0.3868291239669877
Threshold : 0.387 에서 tpr-fpr의 최대값을 찾을 수 있는데,
이것을 활용하여 새로 Classification Report를 만들어보면
#사용하지 않은 일반모드
print( " 0.5 사용")
y_pred_optimal = rand_best_pipe_prob[:,1] >= 0.5
print(classification_report(y_val, y_pred_optimal))
# Optimal Threshold 사용한 모드'
print( " Threshold 사용")
y_pred_optimal = rand_best_pipe_prob[:,1] >= optimal_threshold
print(classification_report(y_val, y_pred_optimal))

위와같은 형태로 Accuracy는 조금 감소하지만 class 1의 f1 score와 recall을 증가시킬 수 있다.
그럼 여기서 Threshold 0.5와 0.62가 어떤 의미를 갖는지 보자.
fig, axes=plt.subplots(1,2, figsize=(18,8))
axes[0].axvline(optimal_threshold,color="red")
axes[1].axvline(0.5,color="red")
sns.histplot(rand_best_pipe_prob,bins=200,ax=axes[0] ).set_title('RandomSearchCV _ Optimal Threshold :: 0.38')
sns.histplot(rand_best_pipe_prob,bins=200,ax=axes[1] ).set_title('RandomSearchCV _ Threshold 0.5')
plt.show()

predict_prob() 함수를 통하여 각 클래스의 판별 확률을 plot하여 선을 그었다.
이게 무슨뜻이냐함은, Threshold값을 기준으로 왼쪽은 1, 오른쪽은 0 으로 판단했다는 것이며 Threshold값이
왼쪽그림은 Optimal Threshold 인 0.38을 기준으로 했을때이고, 오른쪽은 baseline인 0.5를 기준으로 했을때 이다.
0으로 판별받는녀석이 많아지고, 1로 판별받는 녀석이 더 적어진다. -> 진짜 1인녀석들이 남을 가능성이 높아지는것 -> recall이 높아지는것
Threshold값을 통하여, 분류에서 예측값의 클래스 확률값을 통하여 조절을 할 수 있다는것이다.
참조 : arifromadhan19.medium.com/part-1-regression-and-classification-model-evaluation-bc7f6ab3b4dd
Part 1 : Regression and Classification Model Evaluation
An introduction and intuition, how evaluate regression and Classification model in general
arifromadhan19.medium.com
5.4 분류 성능평가 — 데이터 사이언스 스쿨
분류문제는 회귀 분석과 달리 다양한 성능평가 기준이 필요하다. 이 절에서는 분류문제에 사용되는 다양한 성능평가 기준에 대해 알아본다. 이진분류 시스템의 예 제품을 생산하는 제조공장에
datascienceschool.net