본문으로 건너뛰기

020 혼동 행렬 해석하기

키워드: 혼동 행렬, confusion matrix

개요​

혼동 행렬(Confusion Matrix)은 분류 모델의 성능을 상세하게 보여주는 표입니다. 어떤 클래스가 어떤 클래스로 잘못 분류되는지 한눈에 파악할 수 있습니다.

이 글에서는 혼동 행렬을 생성하고, 해석하고, 시각화하는 방법을 알아봅니다.

실습 환경​

  • Python 버전: 3.11 권장
  • 필요 패키지: flaml[automl], scikit-learn, seaborn, matplotlib
pip install flaml[automl] scikit-learn seaborn matplotlib

혼동 행렬 기본 개념​

이진 분류 혼동 행렬​

                      예측
Negative(0) Positive(1)
실제 Negative(0) TN FP
Positive(1) FN TP
용어의미설명
TNTrue Negative음성을 음성으로 정확히 예측
FPFalse Positive음성을 양성으로 잘못 예측 (1종 오류)
FNFalse Negative양성을 음성으로 잘못 예측 (2종 오류)
TPTrue Positive양성을 양성으로 정확히 예측

혼동 행렬 생성​

기본 생성​

from sklearn.metrics import confusion_matrix
import numpy as np

# 020 실제값과 예측값
y_true = [0, 0, 0, 1, 1, 1, 1, 1, 0, 1]
y_pred = [0, 1, 0, 1, 0, 1, 1, 1, 0, 1]

# 020 혼동 행렬 생성
cm = confusion_matrix(y_true, y_pred)

print("혼동 행렬:")
print(cm)

실행 결과​

혼동 행렬:
[[3 1]
[1 5]]

해석:

  • TN = 3: 음성 3개를 정확히 음성으로 예측
  • FP = 1: 음성 1개를 양성으로 잘못 예측
  • FN = 1: 양성 1개를 음성으로 잘못 예측
  • TP = 5: 양성 5개를 정확히 양성으로 예측

각 요소 추출​

tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()

print(f"True Negative (TN): {tn}")
print(f"False Positive (FP): {fp}")
print(f"False Negative (FN): {fn}")
print(f"True Positive (TP): {tp}")

혼동 행렬 시각화​

Seaborn 히트맵​

import seaborn as sns
import matplotlib.pyplot as plt

plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['예측: 음성', '예측: 양성'],
yticklabels=['실제: 음성', '실제: 양성'])
plt.title('Confusion Matrix')
plt.tight_layout()
plt.show()

백분율 표시​

# 020 백분율로 정규화
cm_percent = cm.astype('float') / cm.sum() * 100

plt.figure(figsize=(8, 6))
sns.heatmap(cm_percent, annot=True, fmt='.1f', cmap='Blues',
xticklabels=['예측: 음성', '예측: 양성'],
yticklabels=['실제: 음성', '실제: 양성'])
plt.title('Confusion Matrix (%)')
plt.tight_layout()
plt.show()

숫자와 백분율 함께 표시​

# 020 커스텀 레이블 생성
labels = np.array([[f'{cm[i,j]}\n({cm_percent[i,j]:.1f}%)'
for j in range(cm.shape[1])]
for i in range(cm.shape[0])])

plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=labels, fmt='', cmap='Blues',
xticklabels=['예측: 음성', '예측: 양성'],
yticklabels=['실제: 음성', '실제: 양성'])
plt.title('Confusion Matrix (Count & Percentage)')
plt.tight_layout()
plt.show()

FLAML로 실전 예제​

from flaml import AutoML
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, classification_report

# 020 데이터 로드
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)

# 020 FLAML 학습
automl = AutoML()
automl.fit(
X_train, y_train,
task="classification",
time_budget=30,
verbose=0
)

# 020 예측
y_pred = automl.predict(X_test)

# 020 혼동 행렬
cm = confusion_matrix(y_test, y_pred)

# 020 시각화
plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['악성', '양성'],
yticklabels=['악성', '양성'],
annot_kws={'size': 16})
plt.xlabel('예측', fontsize=14)
plt.ylabel('실제', fontsize=14)
plt.title('유방암 진단 혼동 행렬', fontsize=16)
plt.tight_layout()
plt.show()

# 020 상세 분석
tn, fp, fn, tp = cm.ravel()
print("\n혼동 행렬 상세 분석:")
print(f" 진음성(TN): {tn} - 악성을 악성으로 정확히 진단")
print(f" 위양성(FP): {fp} - 악성을 양성으로 잘못 진단")
print(f" 위음성(FN): {fn} - 양성을 악성으로 잘못 진단")
print(f" 진양성(TP): {tp} - 양성을 양성으로 정확히 진단")

다중 분류 혼동 행렬​

from sklearn.datasets import load_iris

# 020 데이터 로드 (3개 클래스)
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)

# 020 FLAML 학습
automl = AutoML()
automl.fit(X_train, y_train, task="classification", time_budget=30, verbose=0)

# 020 예측
y_pred = automl.predict(X_test)

# 020 혼동 행렬
cm = confusion_matrix(y_test, y_pred)

# 020 시각화
class_names = ['Setosa', 'Versicolor', 'Virginica']

plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=class_names,
yticklabels=class_names,
annot_kws={'size': 14})
plt.xlabel('예측', fontsize=14)
plt.ylabel('실제', fontsize=14)
plt.title('붓꽃 품종 분류 혼동 행렬', fontsize=16)
plt.tight_layout()
plt.show()

혼동 행렬 해석 포인트​

1. 대각선 확인​

대각선 요소는 정확한 예측입니다. 대각선 값이 높을수록 좋습니다.

# 020 대각선 합 (정확한 예측 수)
correct = np.trace(cm)
total = cm.sum()
accuracy = correct / total
print(f"정확도: {accuracy:.4f} ({correct}/{total})")

2. 오분류 패턴 분석​

대각선 외의 값은 오분류입니다. 어떤 클래스가 어떤 클래스로 잘못 분류되는지 확인합니다.

# 020 클래스별 오분류 분석
for i in range(len(cm)):
for j in range(len(cm)):
if i != j and cm[i, j] > 0:
print(f"클래스 {i}가 클래스 {j}로 {cm[i,j]}번 오분류")

3. 행 기준 vs 열 기준​

# 020 행 기준 정규화 (Recall 관점)
cm_row_norm = cm.astype('float') / cm.sum(axis=1, keepdims=True)

# 020 열 기준 정규화 (Precision 관점)
cm_col_norm = cm.astype('float') / cm.sum(axis=0, keepdims=True)

혼동 행렬에서 지표 계산​

def metrics_from_cm(cm):
"""혼동 행렬에서 각종 지표 계산 (이진 분류)"""
tn, fp, fn, tp = cm.ravel()

accuracy = (tp + tn) / (tp + tn + fp + fn)
precision = tp / (tp + fp) if (tp + fp) > 0 else 0
recall = tp / (tp + fn) if (tp + fn) > 0 else 0
specificity = tn / (tn + fp) if (tn + fp) > 0 else 0
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0

return {
'Accuracy': accuracy,
'Precision': precision,
'Recall (Sensitivity)': recall,
'Specificity': specificity,
'F1 Score': f1
}

# 020 사용
metrics = metrics_from_cm(cm)
print("\n혼동 행렬에서 계산한 지표:")
for name, value in metrics.items():
print(f" {name}: {value:.4f}")

혼동 행렬 함수 정리​

def plot_confusion_matrix(y_true, y_pred, class_names=None,
title='Confusion Matrix', figsize=(8, 6)):
"""혼동 행렬 시각화 함수"""
cm = confusion_matrix(y_true, y_pred)

if class_names is None:
class_names = [f'Class {i}' for i in range(len(cm))]

# 백분율 계산
cm_percent = cm.astype('float') / cm.sum() * 100

# 레이블 생성
labels = np.array([[f'{cm[i,j]}\n({cm_percent[i,j]:.1f}%)'
for j in range(cm.shape[1])]
for i in range(cm.shape[0])])

plt.figure(figsize=figsize)
sns.heatmap(cm, annot=labels, fmt='', cmap='Blues',
xticklabels=class_names,
yticklabels=class_names)
plt.xlabel('예측')
plt.ylabel('실제')
plt.title(title)
plt.tight_layout()

return cm

# 020 사용
cm = plot_confusion_matrix(y_test, y_pred,
class_names=['악성', '양성'],
title='유방암 진단 결과')
plt.show()

정리​

  • 혼동 행렬은 분류 모델의 성능을 상세하게 보여줍니다.
  • 대각선은 정확한 예측, 대각선 외는 오분류입니다.
  • TN, FP, FN, TP로 다양한 평가 지표를 계산할 수 있습니다.
  • 다중 분류에서는 어떤 클래스가 어떤 클래스로 혼동되는지 파악합니다.
  • 시각화를 통해 모델의 약점을 직관적으로 파악할 수 있습니다.

다음 글 예고​

다음 글에서는 ROC 곡선과 AUC 시각화에 대해 알아보겠습니다. ROC 곡선을 그리고 해석하는 다양한 방법을 다룹니다.


FLAML AutoML 마스터 시리즈 #020