지도 학습 모델 평가 방법

지도 학습 모델에 대하여 성능을 평가하는 방법을 알아봅니다. 대표적으로 정확도, 정밀도, 재현율, F1-score, ROC-curve 등의 개념을 알아보고 예제를 통해 직접 구현하는 방법을 알아봅니다.

작성: 2024-02-11 00:25 방문: 22
Python ML/DL

지도 학습을 평가하는 방법은 여러가지가 있습니다.

각 평가 지표마다 특성이 다르기 때문에, 데이터 특성, 사용하려는 목적에 따라 알맞은 평가 지표를 선정해야할 필요가 있습니다.

물론, 생성하는 모델에 따라서도 사용할 평가 지표를 잘 선정해야 합니다.



대표적인 지도 학습 평가 지표

  • 분류 문제

    • 혼동 행렬 (confusion matrix)

    • 정확도 (accuracy)

    • 정밀도 (precision)

    • 재현율 (recall)

    • F1값 (F1-score)

    • 곡선하부면적 (AUC, area undr the curve)

  • 회귀 문제

    • 평균제곱오차 (mean square error)

    • 결정계수 (coefficient of determination)


혼동 행렬 (Confusion Matrix)

혼동 행렬은 모델의 예측 결과의 분포를 정답의 참과 거짓에 대해 예측한 참과 거짓 값의 갯수를 계산하여 모델을 평가하는 방식입니다.

주로 참과 거짓의 이진 분류 모델에서 표로 정답과 오답의 갯수를 카운트하여 모델의 성능과 성향을 분석하는데 사용합니다.

  • 정답이 Negative일 때 Negative로 예측하면 TN(True Negative)

  • 정답이 Negative일 때 Positive로 예측하면 FP(False Positive)

  • 정답이 Positive일 때 Negative로 예측하면 FN(False Negative)

  • 정답이 Positive일 때 Positive로 예측하면 TP(True Positive)

이 4가지 상태의 갯수를 이용해 Accuracy, precision, recall, F1 값 등을 계산하게 됩니다.


image

  • 다음은 혼동 매트릭스를 영역으로 표시하는 그림입니다.

  • 가운데 원은 정답이 Positive인 부분이고, 원 바깥쪽은 Negative 값입니다.

  • 원이 나뉜것은 예측 결과로 Positive를 맞춘 부분과 맞추지 못한 부분으로 나뉘기 때문입니다.

  • 바깥영역 또한 정답 Negative를 맞춘 부분과 맞추지 못한 부분으로 나뉩니다.

image

  • 이렇게 영역으로 표시하는 이유는 이후 나오는 Accuracy, Precision, Recall 등을 좀더 쉽게 아해하도록 표현하기 위함입니다.

  • 간단히 설명하면 큰 사각형에서 정답을 기준으로 좌측이 Positive, 우측이 Negative입니다.

  • 원은 예측한 결과입니다. 원에서 좌측 TP는 Positive라고 정답을 정확히 예측하였고, 우측 FP는 정답이 Negative인데 Positive라고 잘못(False) 예측한 결과입니다.

image



Accuracy

  • Accuracy는 전체 데이터 중에 Positive와 Negative를 맞춘 비율입니다.

  • 전체 데이터가 대상이 되는 것에 주의하고, Positive와 Negative 모두 정답을 맞추는 것이 중요한 경우에 유의미한 평가방법입니다.

  • 만일 Positive 갯수가 Negative 에 비해 매우 적은경우, 모두 Negative라고 예측해도 Negative 갯수가 많아 Accuracy가 높게 나올 수 있음을 주의해야 합니다.


Precision

  • Precision은 Positive로 예측한 전체 중에서 실제 정답인 Positive를 예측한 비율입니다.

  • Positive 데이터만 고려하므로 Negative를 얼마나 많이 예측하는지는 중요하지 않고, Positive를 예측한 결과의 정확도가 중요할 때 평가방법입니다.

  • 대상이 Positive라고 예측한 결과이므로, Precision을 높이려면 Positive 예측 양 자체를 높이고, 대신 예측 순도를 높이면 Accuracy는 높아집니다.


Recall

ositive이고 Negative를 고려하지 않기 때문에 Recall 값을 높이려면 Negative 정확도는 낮더라도 Positive를 최대한 많이 맞추는 것이 중요합니다.



F1-score

  • 앞에서 아아본 Precision과 Recall은 각각 특성이 있어서 반대로 단점도 분명히 존재합니다.

  • 이를 보완하기 위해 두 측정 지표를 혼합하여 F1-Score를 계산하여 일반적 성능을 측정합니다.

F1-score를 계산하는 수식은 다음과 같습니다.


image

ROC-curve


  • ROC-curve는 threshold에 따른 FPR(False Positive Rate)와 TPR(True Positive Rate)의 성능을 비교해 보면 평가 방법입니다.

  • 보통 예측 결과를 두 개의 분류로 판단할 때는 중간인 0.5를 Threshold로 하여 평가하게되는데, 이 값을 0~1 사이 값으로 변화시킴에 따라 FPR값과 TPR값이 변화되는데, 이를 좌표 측에 그리고, 선분 아래의 면적을 계산합니다.

  • 다음 그림을 보면 임계값(threshold)를 변경함에 따라 FPR과 TPR값을 출력하여 연결하면 아래 그림과 같이 우측 상단에서 좌측 하단으로 이어지는 선이 이어지고, 해당 선의 아래 면적을 계산할 수 있습니다.

  • 모델이 성능이 나빠 거의 random prediction인 경우 좌측의 worst 사례처럼 직선 형태가 되고, 하단 면적은 삼각형에 해당하는 0.5가 됩니다.

  • 모델 성능이 좋아지면 가운데 그림 better처럼 선이 곡선으로 변경되고 하단 면적은 0.5와 1의 중간 정도가 됩니다.

  • 모델이 최적화된 경우는 우측 그림과 같이 하단 면적의 모양이 사각형에 가까워지고, 면적의 값은 거의 1에 가까워집니다.

  • 참고로 x축인 FPF값은 1-Specificity 로 표기하기도 합니다.

image



모델 평가 예제


데이터 읽어오기

데이터는 sklearn에서 기본적으로 제공하는 breast cancer 데이터를 사용합니다.

breast cancer 데이터는 569개의 샘플로 구성되고, 2개의 class를 갖습니다.

총 30개의 feature를 가지며, 212(M)개와 357(B)의 비율로 Positive와 Negative 데이터 비율이 매우 양호한 축에 속하는 데이터입니다.

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

# 데이터 읽어오기
data = load_breast_cancer()

# 독립 변수
X = data.data

# 종속 변수데이터로 0과 1로 구성
# 0은 정상, 1은 암을 의미하며, 우리는 암을 Positive로 인식하기 위해 0과 1을 뒤바꿔줍니다.
y = 1 - data.target

# Train 데이터와 Test 데이터를 7:3의 비율로 나눕니다.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)


분류 모델 생성하기

분류 모델은 sklearn에서 제공하는 Logistic Regression 모델을 사용합니다.

######################################################################
# 모델 준비
######################################################################

from sklearn.linear_model import LogisticRegression

model = LogisticRegression(solver='lbfgs', max_iter=5000)

print(X_train.shape)
model.fit(X_train, y_train)


Model Predict

y_pred = model.predict(X_test)


예측 결과 평가하기

예측 결과와 정답이 있다면 sklearn의 sklearn.metrics에 포함된 함수들을 이용해 쉽게 평가 지표값을 계산할 수 있습니다.

결과 값은 0에 가까울수록 낮고, 1에 가까울수록 높다고 볼 수 있습니다.

######################################################################
# 결과 평가
######################################################################

from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score

cm = confusion_matrix(y_test, y_pred)
print("confusion matrix", cm)

print("accuracy:", accuracy_score(y_test, y_pred))
print("precision:", precision_score(y_test, y_pred))
print("recall:", recall_score(y_test, y_pred))
print("f1_score:", f1_score(y_test, y_pred))

실행 결과는 다음과 같습니다.

confusion matrix [[106   2]
 [  2  61]]
accuracy: 0.9766081871345029
precision: 0.9682539682539683
recall: 0.9682539682539683
f1_score: 0.9682539682539683
  • confusion matrix의 배열값 [[106 2][2 61]]을 해석해보겠습니다.

  • 첫 번째 [106, 2]는 정답이 Negative일 때 예측한 결과로 Negative로 예측한 TP은 106건, Positive로 예측한 FP은 2건 입니다.

  • 두 번째 [2, 61]은 정답이 Positive일 때 예측한 결과로 Negative로 예측한 FN는 2건, Positive로 예측한 TP는 61건 입니다.


ROC-curve

  • ROC-curve는 threshold에 따른 FPR(False Positive Rate)와 TPR(True Positive Rate)의 성능을 비교해 보면 평가 방법입니다.

  • 보통 예측 결과를 두 개의 분류로 판단할 때는 중간인 0.5를 Threshold로 하여 평가하게되는데, 이 값을 0~1 사이 값으로 변화시킴에 따라 FPR값과 TPR값이 변화되는데, 이를 좌표 측에 그리고, 선분 아래의 면적을 계산합니다.

######################################################################
# ROC Curve
######################################################################

from sklearn.metrics import roc_curve
from sklearn.metrics import roc_auc_score

probas = model.predict_proba(X_test)

fpr, tpr, thresholds = roc_curve(y_test, probas[:, 1])
roc_score = roc_auc_score(y_test, probas[:, 1])

fpr, tpr, thresholds

실행 결과는 다음과 같습니다.

(array([0.        , 0.        , 0.        , 0.00925926, 0.00925926,
        0.01851852, 0.01851852, 0.03703704, 0.03703704, 0.0462963 ,
        0.0462963 , 1.        ]),
 array([0.        , 0.01587302, 0.9047619 , 0.9047619 , 0.92063492,
        0.92063492, 0.96825397, 0.96825397, 0.98412698, 0.98412698,
        1.        , 1.        ]),
 array([           inf, 1.00000000e+00, 9.45948036e-01, 9.33551561e-01,
        9.31439542e-01, 9.07329753e-01, 5.06906786e-01, 3.40514771e-01,
        3.33100102e-01, 2.29814490e-01, 2.03612480e-01, 4.99132939e-08]))

다음은 ROC-curve를 matplotlib을 이용해 그리는 함수의 구현입니다.

import matplotlib.pyplot as plt

def draw_roc(fpr, tpr, roc_score):
    import matplotlib.pyplot as plt
    
    plt.style.use('ggplot')
    
    fig, ax = plt.subplots()
    
    fig.set_size_inches(7, 5)
    
    ax.step(fpr, tpr, 'gray')
    
    ax.fill_between(fpr, tpr, 0, color='orange', alpha=0.4)
    
    ax.set_xlabel('False Positive Rate')
    
    ax.set_ylabel('True Positive Rate')
    
    ax.set_title(f"ROC Curve ({roc_score:.3})")
    
    plt.show()
    
draw_roc(fpr, tpr, roc_score)

위의 코드를 실행하면 아래와 같이 ROC-curve가 그려집니다.

image