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
| 용어 | 의미 | 설명 |
|---|---|---|
| TN | True Negative | 음성을 음성으로 정확히 예측 |
| FP | False Positive | 음성을 양성으로 잘못 예측 (1종 오류) |
| FN | False Negative | 양성을 음성으로 잘못 예측 (2종 오류) |
| TP | True 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