본문으로 건너뛰기

022 혼동 행렬 해석하기

키워드: 혼동 행렬, confusion matrix

개요

혼동 행렬(Confusion Matrix)은 분류 모델의 예측 결과를 시각적으로 요약합니다. 이 글에서는 혼동 행렬을 읽고 해석하는 방법을 배웁니다.

실습 환경

  • Python 버전: 3.11 권장
  • 필요 패키지: pycaret[full]>=3.0

혼동 행렬 구조

이진 분류

                    예측 (Predicted)
Positive Negative
실제 Positive TP FN
(Actual) Negative FP TN

각 요소의 의미:

약어의미설명
TPTrue Positive양성을 양성으로 맞춤
TNTrue Negative음성을 음성으로 맞춤
FPFalse Positive음성을 양성으로 오판 (1종 오류)
FNFalse Negative양성을 음성으로 오판 (2종 오류)

PyCaret에서 혼동 행렬 시각화

from pycaret.classification import *
from pycaret.datasets import get_data

# 022 데이터 로드
data = get_data('diabetes')
clf = setup(data, target='Class variable', session_id=42, verbose=False)

# 022 모델 생성
model = create_model('rf', verbose=False)

# 022 혼동 행렬 시각화
plot_model(model, plot='confusion_matrix')

혼동 행렬에서 지표 계산

import numpy as np

# 022 예시 혼동 행렬
# 022 Pred 0 Pred 1
# 022 Actual 0 50 10
# 022 Actual 1 5 35

TN, FP, FN, TP = 50, 10, 5, 35

# 022 정확도 (Accuracy)
accuracy = (TP + TN) / (TP + TN + FP + FN)
print(f"Accuracy: {accuracy:.4f}") # 0.85

# 022 정밀도 (Precision)
precision = TP / (TP + FP)
print(f"Precision: {precision:.4f}") # 0.7778

# 022 재현율 (Recall)
recall = TP / (TP + FN)
print(f"Recall: {recall:.4f}") # 0.875

# 022 F1 Score
f1 = 2 * precision * recall / (precision + recall)
print(f"F1: {f1:.4f}") # 0.8235

# 022 특이도 (Specificity)
specificity = TN / (TN + FP)
print(f"Specificity: {specificity:.4f}") # 0.8333

다중 분류 혼동 행렬

from pycaret.classification import *
from pycaret.datasets import get_data

# 3-클래스 분류
data = get_data('iris')
clf = setup(data, target='species', session_id=42, verbose=False)

model = create_model('rf', verbose=False)

# 022 다중 클래스 혼동 행렬
plot_model(model, plot='confusion_matrix')

다중 클래스 해석 예시

              setosa  versicolor  virginica
setosa 50 0 0
versicolor 0 47 3
virginica 0 2 48
  • 대각선: 정확한 예측
  • 비대각선: 오분류
  • versicolor 3개가 virginica로 오분류됨
  • virginica 2개가 versicolor로 오분류됨

정규화된 혼동 행렬

비율로 표시하여 클래스 불균형 영향 제거:

from sklearn.metrics import confusion_matrix
import numpy as np

# 022 예측 결과
y_true = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
y_pred = [0, 0, 0, 1, 1, 1, 1, 1, 0, 0]

# 022 일반 혼동 행렬
cm = confusion_matrix(y_true, y_pred)
print("일반 혼동 행렬:")
print(cm)

# 022 정규화 (행 기준 - 실제 클래스별 비율)
cm_normalized = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
print("\n정규화 혼동 행렬 (행 기준):")
print(cm_normalized)

혼동 행렬 해석 실전 예제

from pycaret.classification import *
from pycaret.datasets import get_data

# 022 신용 데이터 (불균형)
data = get_data('credit')
clf = setup(data, target='default', session_id=42, verbose=False)

model = create_model('rf', verbose=False)

# 022 혼동 행렬
plot_model(model, plot='confusion_matrix')

# 022 예측 결과 확인
predictions = predict_model(model)

# 022 실제 혼동 행렬 계산
from sklearn.metrics import confusion_matrix, classification_report

y_true = predictions['default']
y_pred = predictions['prediction_label']

cm = confusion_matrix(y_true, y_pred)
print("혼동 행렬:")
print(cm)

print("\n분류 리포트:")
print(classification_report(y_true, y_pred))

비즈니스 관점 해석

의료 진단 예시

              예측: 양성   예측: 음성
실제 양성 80 20
실제 음성 10 90
  • FN = 20: 실제 환자를 정상으로 오진 (위험!)
  • FP = 10: 정상을 환자로 오진 (추가 검사 필요)
  • 의료에서는 FN을 줄이는 것이 더 중요 → Recall 중시

스팸 필터 예시

              예측: 스팸   예측: 정상
실제 스팸 95 5
실제 정상 2 98
  • FP = 2: 정상 메일을 스팸으로 분류 (중요 메일 놓칠 수 있음)
  • FN = 5: 스팸을 정상으로 분류 (불편함)
  • 스팸 필터에서는 FP를 줄이는 것이 더 중요 → Precision 중시

오류 분석하기

from pycaret.classification import *
from pycaret.datasets import get_data
import pandas as pd

data = get_data('diabetes')
clf = setup(data, target='Class variable', session_id=42, verbose=False)

model = create_model('rf', verbose=False)

# 022 예측
predictions = predict_model(model)

# 022 오분류 샘플 찾기
errors = predictions[predictions['Class variable'] != predictions['prediction_label']]
print(f"오분류 샘플 수: {len(errors)}")
print("\n오분류 샘플 예시:")
print(errors.head())

# 022 FN (양성을 음성으로)
fn_samples = predictions[
(predictions['Class variable'] == 1) &
(predictions['prediction_label'] == 0)
]
print(f"\nFalse Negative 수: {len(fn_samples)}")

# 022 FP (음성을 양성으로)
fp_samples = predictions[
(predictions['Class variable'] == 0) &
(predictions['prediction_label'] == 1)
]
print(f"False Positive 수: {len(fp_samples)}")

정리

  • 혼동 행렬은 분류 결과를 4가지 범주로 요약
  • TP, TN은 정확한 예측, FP, FN은 오류
  • 대각선 값이 클수록 좋은 모델
  • 비즈니스 맥락에 따라 FP/FN의 중요도가 다름
  • 오분류 샘플 분석으로 모델 개선 아이디어 도출

다음 글 예고

다음 글에서는 다중 분류 문제 다루기를 다룹니다.


PyCaret 머신러닝 마스터 시리즈 #022