`혼동 행렬(Confusion matrix)`을 사용하면 분류(Classification) 문제에서 모델의 성능을 평가할 수 있다. TP, TN, FP, FN와 같은 개념들은 이진 분류에서 유명하지만, 멀티 클래스 분류에서도 사용되는 성능 평가 지표들이다. 이진 분류 및 멀티 클래스 분류에서 Confusion matrix을 계산하는 법을 알아보자.
이진 분류에서 TP, TN, FP, FN의 의미
먼저 각 값의 의미에 대해서 알아보자.
- TP(진양성, True Positive): 실제 양성(Positive)이고, 분류모델에서 예측도 양성이라고 판단된 경우이다.
- TN(진음성, True Negative): 실제 음성(Negative)이고, 분류모델에서 예측도 음성이라고 판단된 경우이다.
- FP(위양성, False Positive): 실제 음성(Negative)인데 분류모델에서 예측이 양성이라고 판단된 경우이다.
- FN(위음성, False Negative): 실제 양성(Positive)인데 분류모델에서 예측이 음성이라고 판단된 경우이다.
그림으로 나타내자면 다음과 같다. 이처럼 이진 분류에서 TP, TN, FP, FN 값을 계산하는 것을 간단하다.
이진 분류에서 Recall, Precision, Accuracy 계산하기
위의 값들을 활용하면 쉽게 Recall, Precision, Accuracy 값들을 계산할 수 있다.
- Recall: 실제 양성 샘플 중에서 모델이 정확하게 감지한 양성 샘플의 비율을 알려준다. Recall이 높으면 모델이 실제 양성을 더 잘 감지한다는 것을 의미한다. 계산 공식은
TP/(TP+FN)
이다. - Precision: 모델이 양성으로 예측한 샘플 중에서 실제 양성인 샘플의 비율을 알려준다. Precision이 높으면 모델이 양성으로 예측한 것 중에서 실제로 양성인 비율이 높다는 것을 의미한다. 계산 공식은
TP/(TP+FP)
이다. - Accuracy: 모델의 전반적인 정확도를 제공한다. 즉, 모델에 의해 올바르게 분류된 전체 샘플의 비율을 의미한다. 계산 공식은
(TP+TN)/(TP+TN+FP+FN)
이다.
Recall과 Precision의 분모만 나타내면 다음과 같다.
Confusion matrix는 sklearn 라이브러리를 통해서 간단하게 계산할 수 있다. 먼저 특정 모델을 돌린 결과 y_pred
레이블이 생성되었다고 가정하고 confusion matrix를 계산해주면 다음과 같다.
from sklearn import metrics
# 실제 클래스 레이블과 예측 클래스 레이블이 있다고 가정한다.
y_true = [1, 0, ...]
y_pred = [1, 0, ...]
# metrics 라이브러리를 사용해 Confusion Matrix를 계산한다.
conf_matrix = metrics.confusion_matrix(y_true, y_pred)
# TP, TN, FP, FN을 추출한다.
TN, FP, FN, TP = conf_matrix.ravel()
# Recall을 계산한다.
recall = metrics.recall_score(y_true, y_pred)
# Precision을 계산한다.
precision = metrics.precision_score(y_true, y_pred)
# Accuracy을 계산한다.
accuracy = metrics.accuracy_score(y_true, y_pred)
위의 값을 출력해보면, 다음과 같이 출력되는 것을 볼 수 있다. 이렇게 이진 분류에서의 혼동 행렬은 반드시 2X2 행렬로 만들어진다.
print("Confusion Matrix:")
print(conf_matrix)
print("True Negatives (TN):", TN)
print("False Positives (FP):", FP)
print("False Negatives (FN):", FN)
print("True Positives (TP):", TP)
print("Recall:", recall)
print("Precision:", precision)
print("Accuracy:", accuracy)
>>> 출력 예시
Confusion Matrix:
[[1 2] # TN FP
[1 4]] # FN TP
True Negatives (TN): 1
False Positives (FP): 2
False Negatives (FN): 1
True Positives (TP): 4
Recall: 0.8
Precision: 0.6666666666666666
Accuracy: 0.625
물론 sklearn라이브러리를 사용하지 않고 직접 계산할 수도 있다. 직접 계산한 결과는 라이브러리를 통해 계산한 결과와 당연히 같지만, 값이 계산되는 과정에서 따로 처리해주어야 하는 로직 등이 있다면 이렇게 수동으로 계산하는 방법을 선택해도 된다.
# 실제 클래스 레이블과 예측 클래스 레이블이 있다고 가정한다.
y_true = [1, 0, ...]
y_pred = [1, 0, ...]
# 값 초기화
TP, TN, FP, FN = 0, 0, 0, 0
# TP, TN, FP, FN를 계산한다.
for i in range(len(y_true)):
true, pred = y_true[i], y_pred[i]
if true == 1 and pred == 1:
TP += 1
elif true == 0 and pred == 0:
TN += 1
elif true == 0 and pred == 1:
FP += 1
elif true == 1 and pred == 0:
FN += 1
# Recall, Precision, Accuracy를 계산한다.
recall = TP / (TP + FN) if (TP + FN) > 0 else 0 # 분모가 0보다 큰지 꼭 확인하기
precision = TP / (TP + FP) if (TP + FP) > 0 else 0
accuracy = (TP + TN) / len(y_true)
멀티 클래스 분류에서 TP, TN, FP, FN의 의미
이진 분류와 달리 멀티 클래스 분류의 상황에서는 양성 또는 음성 클래스가 없다. 그렇다면 어떻게 TP, TN, FP, FN 값을 계산할 수 있을까? 다음과 같이 Apple, Banana, Cherry의 3가지 클래스가 있다고 가정해보자. TP의 경우에는 비교적 계산하기 쉽다. Apple을 Apple로 맞추면 TP이다. 그런데 TP, TN, FP, FN는 어떻게 계산할 수 있을까?
멀티 클래스 분류에서 TP, TN, FP, FN를 계산하려면 클래스 별로 계산한 후 각각의 값들을 더해주면 된다. 예를 들어서 Apple, Banana, Cherry와 같이 3개의 클래스가 있다고 가정하면, TP는 Apple을 Apple로 예측한 경우, TN은 Apple이 아닌 것을 Apple이 아니라고 예측한 경우, FP은 Apple이 아닌 것을 Apple로 예측한 경우, FN은 Apple을 Apple이 아니라고 예측 한 경우가 된다. 이 방법대로 모든 클래스의 TP, TN, FP, FN를 계산한 후 평균을 구해주면 전체 클래스의 TP, TN, FP, FN 값을 추출할 수 있다.
멀티 클래스 분류에서 TP, TN, FP, FN 및 Recall, Precision, Accuracy 계산하기
sklearn 라이브러리를 사용하면 이러한 멀티 클래스 분류도 손쉽게 할 수 있다. 이때 recall과 precision을 계산할 때는 average
라는 옵션을 통해서 각 클래스별 평균을 구해줄 수 있다. average
에는 두 가지가 있는데, macro
는 클래스별로 지표를 계산하고 그 값을 단순 평균으로 구하는 옵션이고, weighted
는 클래스별로 지표를 계산하고 그 값을 각 클래스의 샘플 수(weight)로 가중 평균으로 구하는 옵션이다.
from sklearn import metrics
# 실제 클래스 레이블과 예측 클래스 레이블이 있다고 가정한다.
y_true = [1, 2, 0, 1, 2, 0, 2, 1, 0, 1]
y_pred = [1, 2, 0, 1, 2, 1, 2, 1, 0, 2]
# metrics 라이브러리를 사용해 Confusion Matrix를 계산한다.
conf_matrix = metrics.confusion_matrix(y_true, y_pred)
# Recall을 계산한다.
recall = metrics.recall_score(y_true, y_pred, average= "weighted")
# Precision을 계산한다.
precision = metrics.precision_score(y_true, y_pred, average= "weighted")
# Accuracy을 계산한다.
accuracy = metrics.accuracy_score(y_true, y_pred)
멀티 클래스 분류의 경우에는 conf_matrix
가 더 이상 2X2 행렬로 반환되지 않고, 클래스의 개수를 따라간다. 즉, 3개의 클래스가 있을 경우에는 3X3 행렬이 반환된다. 이 값들을 FN= conf_matrix[1, 0] + conf_matrix[2, 0]
처럼 일일히 더하기 보다는 다음과 같이 TP, TN, FP, FN를 구분하는 로직을 만들어서 계산해주면 된다.
# 전체 클래스 리스트
labels = [0, 1, 2, 3, ...]
# 모든 클래스의 TP, TN, FP, FN 총합 초기화
s_tp, s_fp, s_fn, s_tn = 0
for label in labels: # 각 클래스 별 따로 계산해주어야 한다.
# 한 클래스의 TP, TN, FP, FN 총합 초기화
TP, TN, FP, FN = 0, 0, 0, 0
for i in range(len(pred_list)):
# 같은 클래스의 실제값-예측값 쌍을 사용한다.
true = true_list[i] # 같은 클래스의 모든 실제값이 true_list 리스트에 있다.
pred = pred_list[i] # 같은 클래스의 모든 예측값이 pred_list 리스트에 있다.
if (pred == true) and (true == label): #TP
TP += 1
elif(pred == true) and (true != label): #TN
TN += 1
elif(pred != true) and (true == label): #FP
FP += 1
elif(pred != true) and (pred == label): #FN
FN += 1
# 한 클래스의 TP, TN, FP, FN을 더해서 모든 클래스의 총합 구하기
s_tp += TP
s_tn += TN
s_fp += FP
s_fn += FN
참고 글
'🤖AIML' 카테고리의 다른 글
[Keras] keras.layers.Dropout 레이어 이해하기 (0) | 2024.02.21 |
---|---|
[Keras] keras.layers.Flatten 레이어 이해하기 (0) | 2024.02.19 |
[Keras] keras.layers.Dense 레이어 이해하기 (0) | 2024.02.19 |
[트렌스포머 모델 이해하기] Self-Attention에서 Q, K, V(Query, Key, Value)의 의미 (0) | 2024.01.22 |
리눅스에서 Anaconda 설치 및 가상 환경 사용하기 (0) | 2023.12.25 |