예전에 분류 모델의 평가 지표를 살펴보면서 Precision, Recall, Accuracy 등에 대해 정리했었다.
간단히 짚고 넘어가자면,
Precision : Positive로 예측한 것 중 실제 Positive의 비율 (예측이 얼마나 정밀한지 대략적인 파악 가능)
Recall (Sensitivity): 실제 Positive 중 예측이 Positive인 비율 (실제 데이터를 얼마나 잘 재현했는지 파악 가능)
Accuracy : 전체 예측 중 맞은 예측의 비율 (종합적으로 얼마나 정확한지 파악 가능)
이렇게 외우면 Precision 은 정밀도, Recall은 재현율, Accuracy는 정확도로 암기하기도 쉬웠다.
여기에 Specificity의 개념을 더하자면
Specificity : 실제 Negative 중 예측도 Negative인 비율 (일반적으로 Positive의 비율이 높다고 보기 때문에, 특이케이스인 Negative에도 초점을 맞추기 위함)
Specificity는 이렇게 특이도로 외울 수가 있었다.
이런 식으로 4가지 지표를 간단명료하게 정리할 수 있었다. 하지만 위 지표들은 데이터의 분포도에 따라 때로는 바르지 못한 길로 분석가를 인도할 수 있다.
기억나는 한 가지 예를 들어보겠다.
모델을 적용하고자 하는 데이터가 positive의 비율이 압도적으로 높다고 가정해보자. 이 데이터로 학습시켜 어떠한 분류 모델을 만들었는데, 학습이 제대로 진행되지 않은 탓인지 모든 데이터를 positive로 분류해버리고 말았다. 그러나 이 모델의 Precision과 Recall을 확인해본다면, 다음과 같이 아주 높은 수치를 얻을 수 있다.
import numpy as np
from sklearn.metrics import precision_score, recall_score, accuracy_score
# Create an imbalanced dataset
# 99% of samples are positive (class 1), and 1% are negative (class 0)
n_positive_samples = 990
n_negative_samples = 10
y_true = np.concatenate([np.ones(n_positive_samples), np.zeros(n_negative_samples)])
y_pred = np.concatenate([np.ones(n_positive_samples), np.ones(n_negative_samples)])
tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
precision = precision_score(y_true, y_pred)
recall = recall_score(y_true, y_pred)
accuracy = accuracy_score(y_true, y_pred)
print("Precision:", precision)
print("Recall:", recall)
print("Accuracy:", accuracy)
Precision: 0.99
Recall: 1.0
Accuracy: 0.99
따라서 분석가가 이를 인지하지 못하고 모델의 학습이 아주 잘 됐다고 생각하면 큰 낭패를 볼 것이다.
이같은 상황을 해결하기 위해 추가적으로 사용해야 하는 지표인 F1 score 와 ROC curve를 간단히 정리해보겠다.
F1 score
f1 score의 공식은 위와 같다. 즉 F1 score는 Precision과 Recall의 조화평균이다. F1 score는 Precision과 Recall 중 하나만 높고 하나는 낮을 때, 혹은 예측이 한 쪽으로 쏠렸는지를 확인하고 싶을 때 사용하면 좋은 지표로 여겨진다.
예를 들어 Model1의 Precision은 0.9, Recall은 0.5 지만 Model2는 Precision과 Recall 모두 0.7이라고 생각해보자. 얼핏 보면 두 모델 중 뭐가 더 훌륭한지 알 수 없다. 이때 F1 Score를 계산해보면 Model1의 경우는 0.643, Model2의 경우는 0.7로, Model2가 조금 더 좋은 모델임을 알 수 있다. (이를 통해 Precision과 Recall이 모두 높은 모델이 좋은 모델임을 간접적으로 추론 가능하다.)
Precision과 Recall 모두 0부터 1사이의 값을 갖기 때문에, F1 score도 마찬가지로 0에서 1사이의 값을 갖는다. 또한 Precision과 Recall은 모두 예측과 실제가 모두 Positive한 데이터에 관심을 갖는 지표이기 때문에, 처음에 든 예시같은 상황이면 F1 score도 높게 나올 수밖에 없다.
ROC Curve
Positive가 절대적으로 많은 예시상황을 포함해 많은 상황에서 가장 좋은 지표로는 ROC Curve가 있다.
from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib.pyplot as plt
# Calculate ROC curve
fpr, tpr, thresholds = roc_curve(y_true, y_pred)
# Calculate ROC-AUC score
roc_auc = roc_auc_score(y_true, y_pred)
# Plot the ROC curve
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC curve (area = {roc_auc:.2f})')
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.legend(loc='lower right')
plt.show()
ROC Curve는 Receiver Operating Characteristic Curve 의 약자이다. 대충 특징을 표현한다는 의미를 담고 있는 거 같은데, 이 Curve의 X 축을 보면 FP Rete, Y 축을 보면 TP Rate 임이 확인 가능하다. 이때 X 축인 FP Rate는 1 - Specificity와 같은데, Specificty 가 TN / TN + FP 임을 생각해보면, FP Rate는 자연스럽게 1 - Specificity가 된다는 것을 알 수 있을 것이다. TP Rate 또한 자연스럽게 Recall(Sensitivity) 를 나타냄을 생각할 수 있다.
위 코드는 Positive가 절대적으로 많은 예시 상황에서의 ROC Curve를 그릴 수 있는 코드이다. ROC Curve의 밑넓이를 AUC (Area Under Curve) 라고 부르며, 이 AUC 가 모델의 성능을 직접적으로 평가하는 수치가 된다. 위 데이터에선 점수가 고작 0.5밖에 되지 않는데, 모델의 성능을 알려주는 그림이 있어 가져와봤다.
즉, AUC가 크면 클수록 좋은 모델임을 알 수 있다. 그렇다면 어째서 이러한 그래프를 그렸으며, 어떻게 해석할 수 있을까? 단순하게 이해하자면, 예측이 10개 틀리는 동안 90개 맞추면 예측 성공률이 90퍼센트인 좋은 모델이고, 10개 맞추면 반밖에 맞추지 못한 것이므로 랜덤하게 찍은거나 다름 없으며, 1개 맞춘다면 완전히 반대로 예측하고 있는 형편없는 모델이다. ROC Curve는 이 비율을 보여주는 그래프로써, 그 밑넓이를 적분하여 계산하면 모델의 성능을 평가할 수 있는 것이다.
그렇다면 왜 하필 FP랑 TP로 하나요? FN이랑 TN 비율도 있는데?
이는 대전제인, 데이터는 Positive가 Main 취급을 받기 때문이다. 가령 어떤 병의 검사기의 성능을 시험한다고 치면 당연히 실제 환자를 잘 확인해야 하므로, 환자의 비율이 Positive 취급을 받는다. 이런 식으로 더 중요한 데이터, 더 관심있는 데이터에 Positive라는 속성을 보유하므로, ROC Curve를 비롯한 많은 지표들이 Positive에 초점을 맞추고 있는 것이 아닐까? 하는 내 개인적인 생각이다.
'머신러닝' 카테고리의 다른 글
머신러닝 - 스태킹 앙상블과 그 변형에 대해 (4) | 2024.01.07 |
---|---|
머신러닝 - ROC Curve에 대한 확장 : 임계값 (0) | 2023.12.13 |
클러스터링 정리 (K-Means, 계층적 군집화, DBSCAN) (0) | 2023.10.17 |
머신러닝 - 분류모델 평가지표 (Precision, Recall, Accuracy) + 1종, 2종오류 정리 (0) | 2023.07.15 |
머신러닝 - Naive Bayes Classifier(분류) 정리 (0) | 2023.06.17 |