2. 분류(Classification) > 2-7. 평가 metric

평가 metric

평가: sklearn.metrics

2-2 장에서 평가 지표들을 살펴봤습니다. 이번에는 실제로 평가 지표 몇 가지를 코드로 살펴보겠습니다.

(참고)이번 파트에서는 분류 모델의 평가를 알려주는 모듈 위주로 설명합니다. 회귀 평가 지표는 다음 장에서 확인하세요!

참고

1. Accuracy Score

accuracy는 정확도를 의미합니다.

from sklearn.datasets import load_iris
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, confusion_matrix, precision_recall_fscore_support
from sklearn.model_selection import train_test_split

# iris 데이터 불러오기
iris = load_iris()

iris_df = pd.DataFrame(data = iris.data, columns = iris.feature_names)
iris_df['target'] = iris.target
iris_df

X = iris_df.drop('target',1)
Y = iris_df.target

# train_test_split
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.3, random_state = 0)

# 모델 학습 및 예측
clf = SVC(kernel = 'linear').fit(x_train,y_train)
clf.predict(x_train)
y_pred = clf.predict(x_test)

# accuracy
print('Accuracy: ', accuracy_score(y_test, y_pred))

>>>
Accuracy:  0.9777777777777777


데이터 나누고, 학습 시키고, 정확도 측정! 어렵지 않죠?

2. 혼동 행렬(Confusion Matrix)

# 혼동행렬
cm = confusion_matrix(y_test, y_pred) 
print(cm)
>>>
[[16,  0,  0],
[ 0, 17,  1],
[ 0,  0, 11]]

confusion matrix의 각 행렬은 순서대로 setosa, versicolor, virginica라는 target값을 의미합니다. 따라서 (1,1) 위치의 16은 setosa의 TP입니다. Positive로 예측하고, 실제로 True인 경우입니다. (,1) 열의 나머지는 setosa 입장에서 잘못 예측한 값이므로 FP에 해당합니다. setosa와 versicolor는 오류가 없습니다. 하지만 virginica는 12개 중 1개를 versicolor로 잘못 예측했군요. 11/12 = 0.917 정도니까 전체 모델의 정확도accuracy보다 낮습니다. Confusion matrix는 이런 방식으로 어떤 피처, 타겟의 영향력이 떨어지는지 확인하는데 도움을 줍니다.

  • 멀티 클래스의 평가(주의)

iris 데이터의 경우 target 값이 0, 1, 2(setosa, versicolor, virginica)로 세 가지 입니다. 즉, 이진 분류가 아닌 multi class 분류에 해당합니다. confusion matrix의 경우 이진 분류를 기준으로 만들어졌지만, 멀티 클래스 데이터의 분류에도 적용할 수 있습니다. 자세한 내용은 이 블로그를 참고하세요.

from sklearn.metrics import classification_report

print(classification_report(y_test, y_pred))
>>>
              precision    recall  f1-score   support


           0       1.00      1.00      1.00        16
           1       1.00      0.94      0.97        18
           2       0.92      1.00      0.96        11


    accuracy                           0.98        45
   macro avg       0.97      0.98      0.98        45
weighted avg       0.98      0.98      0.98        45

setosa(0), versocilor(1), virginica(2)의 정확도precision, recall, f1-score는 다음과 같군요.

이렇게 classfication_report를 사용하면 여러 지표들을 쉽게 찾을 수 있습니다. 아래는 앞서 설명드리지 않은 macro avg, weighted avg 값 입니다.

  • macro avg = (Positive+Negative) /2 * precision or recall or f1 score

  • weighted avg = Positive/(Positive + Negative) * precision or recall or f1 score

자세한 수식과 해석은 이 블로그를 참고하세요.

3. ROC-AUC

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, confusion_matrix, precision_recall_fscore_support
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
from sklearn.metrics import roc_auc_score, roc_curve, auc

# iris 데이터 불러오기
iris = load_iris()

iris_df = pd.DataFrame(data = iris.data, columns = iris.feature_names)
iris_df['target'] = iris.target
iris_df

X = iris_df.drop('target',1)
Y = iris_df.target

Y = label_binarize(Y, classes=[0,1,2])
n_classes = Y.shape[1]

# train_test_split
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.3, random_state = 0)

# 각 클래스별 학습
clf = OneVsRestClassifier(SVC(kernel = 'linear', probability=True))
y_score = clf.fit(x_train,y_train).decision_function(x_test)

# ROC
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(n_classes):
    fpr[i], tpr[i], _ = roc_curve(y_test[:,i], y_score[:,i])
    roc_auc[i] = auc(fpr[i], tpr[i])

fpr["micro"],tpr["micro"],_ = roc_curve(y_test.ravel(), y_score.ravel())
roc_auc["micro"] = auc(fpr["micro"], tpr["micro"])
# 시각화
plt.figure()
lw = 2
plt.plot(fpr[2], tpr[2], color='darkorange', lw=lw, label = "ROC Curve(are = %0.2f)"%roc_auc[2])
plt.plot([0,1], [0,1], color = 'green', lw = lw, linestyle = '--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0,1.05])
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")

plt.legend(loc = "lower right")
plt.show()

roc curve

## 다중 클래스 ROC
from scipy import interp

# 전체 False Positive Rate
all_fpr = np.unique(np.concatenate([fpr[i] for i in range(n_classes)]))

# ROC 곡선 보간
mean_tpr = np.zeros_like(all_fpr)
for i in range(n_classes):
    mean_tpr += interp(all_fpr, fpr[i], tpr[i])

# 평균
mean_tpr /= n_classes

fpr["macro"] = all_fpr
tpr["macro"] = mean_tpr
roc_auc["macro"] = auc(fpr["macro"], tpr["macro"])

# plot - micro
plt.plot(fpr["micro"], tpr["micro"],
         label ='micro-avarage ROC curve (are = {0:0.2f})'
            ''.format(roc_auc["micro"]))

# plot - macro
plt.plot(fpr["macro"], tpr["macro"],
         label ='micro-avarage ROC curve (are = {0:0.2f})'
            ''.format(roc_auc["macro"]))

for i in range(n_classes):
    plt.plot(fpr[i], tpr[i], lw=lw,
             label='ROC curve of class {0} (area={1:0.2f})'
             ''.format(i, roc_auc[i]))
    
plt.plot([0,1],[0,1], 'k--', lw=lw)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.legend(loc="lower right")
plt.show()

multiple roc curve

class 0, 1, 2. 그러니까 setosa, versicolor, virginica 모두 높은 roc-auc 값을 갖는군요. 이때 micro, macro average는 평균을 내는 방식입니다.

  • macro average: 각각의 roc-auc 값을 더하고 'class의 개수'로 나눈 값, 즉 평균입니다. 지금은 3개로 나눴군요.
  • micro average: 개수 그자체로의 평균입니다. 아까 confusion matrix에서 16, 17, 11, 1 값 기억나시나요? 그 값 자체로 평균을 낸 값입니다.

정리하면 macro average는 값의 평균, micro average는 raw한 fpr, tpr 값들의 평균이라고 할 수 있겠네요.

위 코드는 sklearn 공식 API와 이를 활용한 블로그1, 블로그2를 참고했습니다.

마지막으로 업데이트 된 날짜:
2022년 10월 30일