본문 바로가기
Python notes/Statistical Analysis

파이썬) 혼동행렬 그리고 정확도, 정밀도, 민감도, f1 score 등 계산하기 (+heatmap, confusion_matrix, classification_report)

by 성실한 나무 2021. 7. 18.

#1. 혼동행렬은 무엇인가?

혼동행렬은 분류 모델의 성능을 평가하는 지표로서 영어로는 confusion matrix라고 하며 혼돈행렬, 정오행렬, 오분류표 등으로도 불린다. 지도학습을 통해 모델링한 "분류 모델이 예측한 값"과 레이블되어 있는 "원래의 값" 간의 관계를 표로 나타낸다. 이 표를 통해 해당 모델의 정확도(accuracy), 정밀도(precision), 민감도(sensitivity), f1 score 등을 파악할 수 있으며, 이 중에서도 특히 정확도를 통해 해당 모델이 정확하게 분류해 낼 수 있는 비율을 지 확인할 수 있다.

  실제값(P-실제로 맞다) 실제값(N-실제로 틀리다)
모델의 예측값 (P로 예측-맞다고 예측) TP FP
모델의 예측값 (N로 예측-틀리다고 예측) FN TN

일반적으로 혼동행렬은 위와 같이 행에 모델의 예측값의 두 경우(Positive, Negative)를 놓고, 열에 실제 값의 두 경우(Positive, Negative)를 놓는데, 예측값과 실제값의 위치를 바꾸어 놓는 경우도 있다. 이런 경우, TP, FP, FN, TN의 자리가 변경되어서 각종 지표들을 계산하는 것이 헷갈릴 수 있으므로 자리를 기억하기보다는 예측값과 실제값의 조합에 따른 Case를 잘 이해해두는 것이 좋다. 혼동행렬은 총 4개의 경우의 수, 셀값을 가지는데 이는 "두개의 알파벳"으로 기억하면 된다. 첫번째 알파벳은 예측값과 실제값과 동일한지 여부를 나타내고 동일한 경우는 T(True), 상이하면 F(False)로 적는다. 두번째 알파벳은 모델이 예측한 값을 나타내는데 모델의 예측값이 P(Positive)이면 P, 모델이 예측을 N(Negative)로 했으면 N이 된다.

 

 

#2. 혼동행렬로부터 정확도, 정밀도, 민감도, f1 score 계산하기

혼동행렬의 셀값을 활용해서 해당 모델을 평가하기 위한 여러 지표들을 아래와 같이 계산할 수 있다. 

 1) 정확도(accuracy): (TP+TN) / (TP+TN+FP+FN)

 2) 정밀도(precision): TP / (TP+ FP)

 3) 민감도(sensitivity = 재현율 recall): TP / (TP+FN)

 4) f1 score: 2 * 정밀도* 민감도 / (정밀도+민감도)

 

 

#3. 파이썬으로 혼동행렬 구하기

반응형

파이썬으로 혼동행렬을 구하기 위해서는 sklearn 패키지를 설치한 후에 아래 코드와 같이 confusion_matrix, classification_report, precision_score, recall_score, f1_score 함수를 import 해야 한다.

1
2
3
4
5
6
7
from sklearn.metrics import classification_report, confusion_matrix, 
precision_score, recall_score, f1_score
import seaborn as sns
 
cm2 = confusion_matrix(comp_df['실제값'],comp_df['예측값'])
cmdf2 = DataFrame(cm2, index=['실제값(N)''실제값(P)'], columns=['예측값(N)''예측값(P)'])
cmdf2
 
cs

여기서 예측 모델은 비행기가 정시에 도착할지 여부를 예측하는 분류 모델로서, 비행기가 정시에 도착하는 경우는 1, 비행기가 연착하는 경우는 0으로 표시되어 있다.

comp_df는 이 모델이 각 케이스의 데이터를 바탕으로 정시에 도착할 경우1과 연착할 경우 0으로 "예측한 값"과 실제로 해당 케이스에 정시에 도착했는지, 연착했는지 "실제값"을 비교해 놓은 데이터 프레임이다. 

두 값이 일치하면 해당 케이스를 맞게 분류한 것이고, 두 값이 불일치하면 틀리게 분류한 것으로 볼 수 있다.

 

먼저, 혼동행렬은 confusion_matrix(데이터 상의 실제값열, 모델의 예측값열)를 위의 코드와 같이 실행하여 2차 리스트 형태인 혼동행렬을 간단히 구할 수 있다. 그런데 2차 리스트 형태로 나오고 별다른 설명이 없기 때문에 각 값이 무엇을 의미하는지 이해하기 어렵다. 그래서 혼동행렬 함수를 통해 얻은 리스트를 바탕으로 인덱스와 컬럼을 추가하여, 아래 코드와 같이 이해하기 쉬운 데이터 프레임 형태로 혼동행렬을 출력할 수 있다. 

혼동행렬 데이터프레임

 

데이터 프레임 형태의 혼동행렬은 seaborn의 heatmap을 통해 추가적으로 시각화를 할 수 있는데

이 경우에도 xlabel, xticks 등을 통해 라벨링을 적절히 해주어야 한다.

heatmap으로 혼동행렬을 시각화 하는 코드는 아래와 같고 그 결과는 왼쪽 이미지와 같다. heatmap 파라미터 중에서 annot은 혼동행렬 상에 각 케이스의 숫자를 나타낼지 여부를 뜻하고, fmt은 format을 의미하며 'd'는 decimal 즉 십진수 형태로 숫자를 표기하라는 뜻이다. cmap 파라미터는 color map으로서 heatmap의 색상을 설정할 수 있다.

1
2
3
4
5
6
7
8
 
sns.heatmap(cm2, annot = True, fmt = 'd',cmap = 'Reds')
plt.xlabel('실제값')
plt.ylabel('예측값')
plt.xticks([0.5,1.5],['0(N)''1(P)'])
plt.yticks([0.5,1.5],['0(N)''1(P)'])
plt.show()
 
cs

 

 

#4. 파이썬으로 혼동행렬 성능지표 구하기: 정밀도, 재현율(민감도), F1 Score

파이썬으로 혼동행렬 성능지표를 구하기에 앞서 각 TP, TN, FP, FN의 각 케이스 값과 성능지표(정밀도, 재현율, F1 Score)를 수기로도 계산해보았다. 과연 수기로 계산한 값과 파이썬의 함수로 구한 값이 동일한지 확인하고 싶었기 때문이다.

아래 코드를 실행하면 왼쪽과 같은 결과 값이 출력된다. (정밀도 0.807, 재현율 1, f1 0.893)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#정시에 도착한 경우= 1, 비행기가 연착된 경우= 0
TP=len(comp_df.query("실제값==1 and 예측값==1")) 
TN= len(comp_df.query("실제값==0 and 예측값==0"))
FP= len(comp_df.query("실제값==0 and 예측값==1"))
FN= len(comp_df.query("실제값==1 and 예측값==0"))
print("TP", TP) #ontime= 1, delay= 0
print("TN", TN)
print("FP", FP)
print("FN", FN)
print("precision", TP/(TP+FP))
print("recall", TP/(TP+FN))
pc=TP/(TP+FP)
rc=TP/(TP+FN)
print("f1 score"2*pc*rc/(pc+rc))
cs

 

파이썬으로 위의 값을 구하는 방법은 두 가지가 있다. 사이킷런 패키지에 있는 함수들을 불러오는데, classification_report라는 함수를 통해 레포트 형태로 한번에 precision, recall, f1-score를 불러오는 방법이 있고, 각각의 값을 precision_score, recall_score, f1_score라는 함수로 계산하는 형태가 있다. 어느 경우이든지 각 함수에 넣는 파라미터는 혼동행렬과 마찬가지로 실제값, 예측값 순서로 입력해야 한다. classification_report의 경우 1에 해당하는 행 값(정밀도 0.81, 재현율 1, f1 0.89)을 확인하면 된다. 아래와 같이 각 대응되는 값이 동일한 것을 확인할 수 있다. 

classification_report, precision_score, recall_score, f1_score

앞서 수기로 계산한 성능지표 값과 비교해보아도 동일한 것을 확인할 수 있었다.

댓글