본문으로 건너뛰기

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