본문 바로가기
머신러닝

[머신러닝] 성능 평가 지표

by PIAI 2022. 5. 4.

회귀 평가 지표

 

성능 평가 지표는 일반적으로 모델이 분류냐 회귀냐에 따라 여러 종류로 나뉩니다. 

먼저 회귀의 평가 지표를 보면 

 

MSE(Mean Squared Error)

실제 값과 예측 값의 차이를 제곱해 평균한 것

RMSE(Root Mean Squared Error)

MSE는 제곱을 한 것이라 오류값이 커질수도 있으므로 루트를 씌운 것

MAE(Mean Absolute Error)

실제 값과 예측 값의 차이를 절댓값으로 변환해 평균한 것

 

MSLE (Mean Squared Log Error)

MSE에 로그를 적용해준 것, 평균이나 예측값이 0이 되면 잔차가 무한대로 수렴하므로 +1을 해줌

RMSLE (Root Mean Squared Log Error)

RMSE에 로그를 적용해준 것

R² (R Sqaure)

  분산 기반으로 예측 성능을 평가합니다. 1에 가까울수록 예측 정확도가 높습니다.

R² = 예측값 Variance / 실제값 Variance

y^: 예측값

y-: 평균

 

분류 평가 지표

 

대표적으로 맞았냐 틀렸냐를 구분하는 정확도가 있습니다. 하지만 이진 분류의 경우 데이터의 구성에 따라 ML 모델의 성능을 왜곡할 수 있기 때문에 정확도 하나 가지고 성능을 평가하지 않습니다.

 

예를들어 신용카드사기를 예측하는 프로그램이 있다고 가정해 봅시다. 일반적으로 사기보다는 사기를 치지 않는 사람이 대다수입니다. 사기건수가 1%, 사기를 치지않는 건수를 99%라고 했을 시, 전부 사기를 치지않는다고 판단하는 ML모델을 만들면 이 모델의 정확도는 99%입니다.

 

그럼 직관적으로 봤을 때 이 모델이 좋은모델인가요?? 정확도로 판단했을때는 엄청나게 좋은 모델이지만, 내면을 보면 사기 건수는 하나도 잡지못하는 모델입니다. 이를 위해 필요한 것이 오차행렬입니다.

 

 

오차행렬

 

이진 분류에서 성능 지표로 잘 활용되는 오차행렬(confusion matrix, 혼동행렬)은 예측을 수행하면서 얼마나 헷갈리고(confuse) 있는지도 함께 보여주는 지표입니다.

 

4분면의 위, 아래를 실제 클래스 값 기준으로 Negative, Positive로 분류하고, 왼쪽, 오른쪽을 예측 클래스 값 기준으로 

Negative, Positive로 분류합니다.

 

 

  • TN는 예측값을 Negative 값 0으로 예측했고, 실제값 역시 Negative 값 0
  • FP는 예측값을 Positive 값 1로 예측했는데, 실제 값은 Negative 값 0
  • FN는 예측값을 Negative 값 0으로 예측했고, 실제 값은 Positive 값 1
  • TP는 예측값을 Positive 값 1으로 예측했고, 실제값 역시 Positive 값 1

TP, TN, FP, TN 값으로 Classifier 성능의 여러 면모를 판단할 수 있는, 정확도(Accuray), 정밀도(Precision), 재현율(Recall) 값을 알 수 있습니다.

 

  • 정확도 = 예측 결과와 실제 값이 동일한 건수 / 전체 데이터 수 = (TN + TP)/(TN + FP + FN + TP)
  • 정밀도 = TP / (FP + TP)
  • 재현율 = TP / (FN + TP)

정밀도는 예측을 Positive로 한 대상 중에 예측과 실제 값이 Positive로 일치한 데이터이고,

재현율은 실제 값이 Positive인 대상 중에 예측과 실제 값이 Positive로 일치한 데이터입니다. 민감도(Sensitivity) 또는 TPR(True Positive Rate)라고도 불립니다.

 

그럼 재현율와 정밀도가 왜 중요한지 알아보면, 재현율이 중요한 지표는 실제 Positive 양성 데이터를 Negative로 잘못 판단하면 큰 리스크를 가져오는 경우입니다. 예를들어 암 환자가 있는데 이 환자가 암(Positive)인데, 암이 아니다(Negative)로 판단하면 이 환자는 암인지 모르고 살다가 사망하는 불상사가 발생합니다.

 

정밀도가 중요한 지표는 실제 Negative 데이터를, Positive로 잘못 판단하면 리스크를 가져올 경우입니다. 스팸메일을 구분하는 프로그램이 있다고 가정해봅시다. 만약 중요한 메일이 스팸이 아닌데(Negative) 스팸이라 판단(Positive)하면 

이 메일은 메일함으로 도착하지도 않고 기각되어 버립니다.

 

결론으로 재현율은 FN(실제 Positive, 예측 Negative)를 낮추는 데, 정밀도는 FP(실제 Negative, 예측 Positive)를 낮추는 데 중점을 둡니다.

 

그럼 이제 암 환자 진단를 오차행렬, 정확도, 정밀도, 재현율로 확인해보겠습니다.

 

from sklearn.metrics import accuracy_score, precision_score, recall_score, confusion_matrix, accuracy_score
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

cancer = load_breast_cancer()
data = cancer['data']
target = cancer['target']

train_x, test_x, train_y, test_y = train_test_split(data, target, test_size=0.2, stratify=target)

lg_clf = LogisticRegression()
lg_clf.fit(train_x, train_y)
pred = lg_clf.predict(test_x)

print(f"정확도 : {accuracy_score(test_y, pred):.4f}")
print(f"정밀도 : {precision_score(test_y, pred):.4f}")
print(f"재현율 : {recall_score(test_y, pred):.4f}")
print(f"오차행렬 :\n {confusion_matrix(test_y, pred)}")

 

정밀도/재현율 트레이드오프

 

정밀도 또는 재현율이 특별히 강조돼야 할 경우 결정 임곗값(Threshold)을 조정해 정밀도 또는 재현율의 수치를 높일 수 있습니다. 정밀도와 재현율은 상호 보완적인 평가 지표이기 때문에 어느 한쪽을 강제로 높이면 한쪽은 떨어집니다.

이를 트레이드오프(Trade-off)라고 합니다.

 

사이킷런의 예측 확률을 반환하는 predict_proba를 이용하여 임곗값을 조정하면서 어떻게 재현율과 정밀도가 변화하는지 코드로 확인해보겠습니다.

 

pred_proba = lg_clf.predict_proba(test_x)
pred = lg_clf.predict(test_x)

for i in range(3):
    print(i, 'predict proba의 예측확률: {:4f} {:4f}'.format(pred_proba[i][0], pred_proba[i][1]))
    print('predict', pred[i])
    print()

임곗값을 조정하는 Binarizer를 사용할 건데, 임곗값보다 같거나 작으면 0, 크면 1값으로 반환합니다.

from sklearn.preprocessing import Binarizer

X = [[1, 0, 0],
     [-1, 1, -1],
     [-1 ,0.9 ,1]]

b = Binarizer(threshold=0.9)
print(b.fit_transform(X))

# Positive 클래스만 Binarizer에 적용
pred_proba_1 = pred_proba[:, 1].reshape(-1, 1)

b = Binarizer(threshold=0.5)
pred = b.fit_transform(pred_proba_1)

print(f"before 정확도 : {accuracy_score(test_y, pred):.4f}")
print(f"before 정밀도 : {precision_score(test_y, pred):.4f}")
print(f"before 재현율 : {recall_score(test_y, pred):.4f}")
print(f"before 오차행렬 :\n {confusion_matrix(test_y, pred)}")
print()

b = Binarizer(threshold=0.1)
pred = b.fit_transform(pred_proba_1)

print(f"after 정확도 : {accuracy_score(test_y, pred):.4f}")
print(f"after 정밀도 : {precision_score(test_y, pred):.4f}")
print(f"after 재현율 : {recall_score(test_y, pred):.4f}")
print(f"after 오차행렬 :\n {confusion_matrix(test_y, pred)}")
print()

임곗값이 낮을수록 Positive로 예측할 확률이 올라가므로 재현율이 올라가고,

임곗값이 높을수록 Positive로 예측할 확률이 낮아지므로 재현율이 낮아집니다.

 

반대로,

임곗값이 낮을수록 Positive로 예측할 확률이 올라가므로 정밀도가 낮아지고,

임곗값이 높을수록 Positive로 예측할 확률이 낮아지므로 정밀도가 올라갑니다.

 

 

F1 스코어

 

F1 스코어는 정밀도와 재현울이 어느 한쪽으로 치우치지 않는 수치를 나타낼 때 상대적으로 높을 값을 가집니다.

 

 

 

ROC-AUC

 

ROC곡선과 이에 기반한 AUC 스코어는 이진 분류의 예측 성능 측정에 중요하게 사용되는 지표입니다. 

ROC 곡선은 FPR(False Positive Rate)이 변할 때 TPR(TRUE Positive Rate)이 어떻게 변하는지 나타내는 곡선입니다.

 

TPR은 재현율을 나타내고 TP/(FN+TP) 이고, 민감도라고도 불립니다. 민감도에 대응하는 지표로 TNR(True Negative Rate)이라고 불리는 특이성(Specificity)이 있습니다.

 

  • 민감도(TPR)는 실제값 Positive(양성)가 정확히 예측돼야 하는 수준입니다.
  • 특이성(TNR)은 실제값 Negative(음성)가 정확히 예측돼어야 하는 수준입니다.

TNR = TN / (FP + TN)

FPR = FP / (FP + TN) = 1 - TNR

 

 

roc 곡선

 

왼쪽 하단과 오른쪽 상단 대각선은 동전을 무작위로 던져 앞/뒤를 맞추는 랜덤 수준의 이진 분류 ROC 직선입니다.(AUC 는 절반 면적인 0.5)

ROC 곡선이 가운데 직선에서 멀어질수록 성능이 뛰어난 것입니다. 결정 임곗값을 0부터 1까지 변경하면서 FPR과 TPR의 값을 그래프로 그리면 ROC 곡선이 나옵니다.

 

from sklearn.metrics import roc_curve, roc_auc_score
import numpy as np
import matplotlib.pyplot as plt

proba = lg_clf.predict_proba(test_x)[:, 1]

fprs, tprs, thresholds = roc_curve(test_y, proba)
print("임계값 : ", np.round(thresholds[1:], 2))
print("FPR : ", np.round(fprs[1:], 2))
print("TPR : ", np.round(tprs[1:], 2))
print("ROC AUC 값 : ", np.round(roc_auc_score(test_y, proba), 4)) # 예측값을 뒤에
plt.plot(fprs, tprs, color='orange');
plt.plot((0, 1), (0, 1), 'k--', color='blue');
plt.xticks(np.arange(0, 1.1, 0.1));
plt.xlabel('FPR')
plt.ylabel('TPR')

 

댓글