머신러닝) 분류 모델을 평가하는 방법: 혼동행렬 (+다중분류모델 평가 예제)
적합된(fitted) 분류 모델이 데이터를 얼마나 잘 분류해 낼 수 있는지 성능을 평가하기 위한 여러가지 방법이 있다. 그 중에서 가장 보편적으로 쓰이는 방법 중 하나가 혼동행렬이다. 여기서는 이진분류 모델을 기준으로 혼동행렬의 개념을 확인하고, 파이썬으로 혼동행렬을 구해보려고 한다. 혼동행렬은 수기 계산법과 파이썬의 함수를 이용하는 방법으로 계산한다. 그 다음 다중분류 모델을 평가하는 혼동행렬을 파이썬 함수를 통해 구하고 그 내용을 파악하고자 한다.
혼동행렬(Confusion matrix)이란 무엇인가?
혼동행렬은 응답 유형별로 정확한 예측과 잘못된 예측의 수를 한 번에 보여주는 표다. 또한, 혼동행렬에 나타나는 예측의 수들(TP, FN, FP, TN)을 조합하여 각종 지표들(정확도, 민감도, 특이도, 정밀도, 재현율, F1 Score)을 계산함으로써 좀 더 유의미한 평가를 할 수 있다.
아래에서는 혼동행렬을 설명하기 위해 흔히 사용되는 이진분류 모델의 혼동행렬을 통해 각 지표들의 의미를 확인한다. 이진분류 모델은 응답변수(혹은 종속변수 혹은 타겟변수)의 값을 2가지만 갖는 모델이다. 예를 들면, 양성 혹은 음성으로 분류되거나 합격 혹은 불합격으로 분류되는 경우이다. 이런 경우, 보통은 데이터 수가 상대적으로 작은(희귀한) 클래스가 관심의 대상이 되므로 통상적으로 이를 1로 지정하고, 반대로 수가 많은 경우를 0으로 지정한다. 즉, 일반적인 경우에는 1이 더 중요한 사건을 의미한다. 이에 따라 양성은 1, 음성은 0으로 분류하고, 합격은 1, 불합격은 0으로 분류할 수 있다.
TP, FN, FP, TN
파이썬에서는 혼동행렬을 구하기 위해 Scikit Learn의 confusion_matrix 함수를 사용한다. 함수에 넣는 파라미터는 순서대로 실제값 리스트(y_test)와 예측값 리스트(y_pred)를 입력한다. 이렇게 반환 받은 배열을 바탕으로 Pandas의 DataFrame 함수를 사용해서 인덱스와 컬럼명을 지정하면 아래와 같이 이해하기 쉬운 혼동행렬을 얻을 수 있다.
혼동행렬의 예측의 수들 중에서 실제값이 Positive(1)인데 모델이 Positive(1)로 예측한 경우의 수 "119"는 TP(True Positive)라고 한다. 실제값이 Positive(1)인데 모델이 Negative(0)로 잘못 예측한 경우의 수 "2"는 FN(False Negative)라고 한다. 실제값이 Negative(0)인데 모델이 Negative(0)로 예측한 경우의 수 "61"은 TN(True Negative)라고 한다. 마지막으로 실제값이 Negative(0)인데 모델이 Positive(1)로 잘못 예측한 경우의 수 "6"은 FP(False Positive)라고 한다.
아래는 실제값과 예측값을 짝지은 데이터프레임에서 TP, TN, FP, FN의 경우의 수를 센 값이다. 앞서 구한 혼동행렬에서의 각 예측의 수들이 어떤 종류인지 확인할 수 있다.
성능 측정 지표: 정확도, 민감도, 특이도, 정밀도, 재현율, 그리고 F1 Score
각 예측의 수들을 조합하고 계산하여 모델 성능을 평가하는 지표들을 구할 수 있다. 먼저, 정확도(Accuracy)는 전체 예측의 수에서 옳게 예측한 수를 나눈 값이다. 즉, (TP+TN) / (TP + TN + FP + FN)로 구한다. 하지만 정확도 자체는 네 가지 가능한 구역의 값들을 하나로 묶어 버려서 결과 값들에 대해서는 아무런 정보를 주지 못한다. 예를 들어, 인터넷 쇼핑몰의 방문객 중 0.1%만이 실제 구매를 한다면, '모든 방문객이 구매를 하지 않을 것이다'라고 예측하는 모델의 정확도는 99.9%가 될 것이다. 하지만 이 모델은 결국 있으나 마나다.
좋은 모델이란, 1로 예측한 값들 중에 실제로 1인 값의 비율이 높아야 하고, 0으로 예측한 값들 중에 실제로 0인 값의 비율이 높은 모델이어야 한다. 전체 정확도는 높더라도 1만 분류를 잘하고 0을 분류를 잘 못한다든지, 0만 분류를 잘하고 1은 분류를 잘 못하는 분류 모델은 분류 기능을 제대로 수행한다고 볼 수 없기 때문이다.
이에 따라 분류기의 성능을 해석해 줄 수 있는 두 쌍의 상호 보완적인 측정법이 있는데 바로 민감도(Sensitivity), 특이도(Specificity), 정밀도(Precision), 그리고 재현율(Recall)이다. 각 값을 구하는 식은 아래 파이썬 코드에서 확인할 수 있다. 참고로 민감도와 재현율을 구하는 공식은 같다.
민감도는 실제 1인 값들 중에서 1이라고 예측한 값들의 비율을 나타내며, 특이도는 실제 0인 값들 중에서 0이라고 예측한 값들의 비율을 나타낸다. 정밀도는 1이라고 예측한 값들 중에서 실제 1인 값들의 비율을 나타내고, 재현율은 실제 1인 값들 중에서 1이라고 예측한 값들의 비율을 나타낸다. 이 지표들은 정확도보다 더 많은 정보를 제공한다.
이 중에서도 정밀도와 재현율은 두개의 개념을 합쳐서 F1 Score라는 하나의 값으로 표현할 수 있는데 이는 F1 score = 2 x (정밀도 x 재현율) / (정밀도 + 재현율)로 정의된다.
분류 모델이 효과적인지 여부는 이와 같은 지표들을 전반적으로 확인함으로써 판단할 수 있다.
다중분류 모델의 혼동행렬 구하기
한편, 분류 모델의 반응변수는 항상 두가지인 것은 아니다. 이렇게 세가지 이상의 반응변수 값을 갖는 분류 모델을 다중분류 모델이라고 한다. 다중분류 모델의 성능을 평가하기 위해서는 클래스들(반응변수들) 중 하나를 positive 기준으로 삼고 나머지를 negative 기준으로 두는 이진분류 모델들을 구해야 한다. 이 때 각 모델들에 대한 혼동행렬을 구하고 각 혼동행렬에서 나오는 성능 측정 지표들의 평균을 구함으로써 다중분류 모델의 성능 측정 지표값을 구한다.
파이썬에서는 Scikit Learn의 multilabel_confusion_matrix 함수를 통해 아래와 같이 다중분류 모델의 혼동행렬들을 구할 수 있다. 아래는 분류값의 타입이 multilabel-indicator인 경우이고, 분류값의 타입이 multiclass인 경우에는 labels 파라미터에 전체 분류값을 리스트로 입력해주어야 한다. 이와 관련한 자세한 내용은 Scikit Learn 공식 홈페이지의 sklearn.metrics.multilabel_confusion_matrix 문서에서 확인할 수 있다.
위의 예시에서 분류값 0을 기준으로 이진분류한 혼동행렬의 경우, 0이 P(Positive)가 되고, 나머지 분류값인 1, 2가 N(Negative)가 된다. 이에 따라 실제값 0을 0으로 예측한 경우가 TP, 실제값 1 또는 2를 1 또는 2로 예측한 경우가 TN, 실제값 0을 1 또는 2로 예측한 경우가 FN, 실제값 1 또는 2를 0으로 예측한 경우가 FP이다.
동일한 방식으로 나머지 행렬에서도 각 TP, TN, FP, FN을 구할 수 있고 이로부터 측정 지표값을 계산할 수 있다. 이 측정 지표값들의 평균을 구해서 해당 다중 모델의 성능 측정 지표값으로 사용하는 것이다.
앞서 이진분류 모델에서 사용한 파이썬 함수들(precision_score, recall_score, f1_score)로도 다중 분류 모델의 측정 지표값들을 구할 수 있다. 다만 입력값 중에 average라는 파라미터가 추가되어야 한다. average의 옵션으로는 micro, macro, weighted가 있는데 결과값은 유사한 것으로 보인다.
[참고문헌]
스티븐 마슬랜드, 알고리즘 중심의 머신러닝 가이드 제2판 Machine Learning: An Algorithmic Perspective, Second Edition (경기: 제이펍, 2017), 29
피터 브루스, 앤드루 브루스, 피터게데크, Practical Statistics for Data Scientists: 데이터 과학을 위한 통계 2판 (서울: 한빛미디어(주), 2021), 252~261
sklearn.metrics.multilabel_confusion_matrix, Scikit Learn, 2021, https://scikit-learn.org/