Skip to content

Konfusionsmatrix in Sklearn: So bewertest du Klassifikationsmodelle

Updated on

Dein Klassifikationsmodell meldet 95% Accuracy, also deployest du es. Dann stellst du fest, dass es 80% der positiven Fälle verpasst, die dich eigentlich interessieren – betrügerische Transaktionen, Krankheitsdiagnosen, fehlerhafte Produkte. Accuracy allein verschleiert kritische Informationen darüber, wo und wie ein Modell scheitert.

Eine einzelne Accuracy-Zahl reduziert alle Fehlerarten auf eine einzige Kennzahl. Ein Spamfilter, der jede Spam-Mail durchlässt und alle legitimen E-Mails korrekt klassifiziert, erreicht trotzdem eine hohe Accuracy, wenn Spam nur 5% des Gesamtvolumens ausmacht. Du musst das vollständige Bild sehen: Wie viele Positive erkennt das Modell, wie viele Negative klassifiziert es falsch, und wo genau treten die Fehler auf?

Die Konfusionsmatrix zerlegt die Modellleistung in ihre vier Komponenten – True Positives, True Negatives, False Positives und False Negatives. Zusammen mit abgeleiteten Metriken wie Precision, Recall und F1-Score erhältst du verwertbare Einblicke in das, was dein Modell richtig und falsch macht. Scikit-learn stellt confusion_matrix, classification_report und ConfusionMatrixDisplay bereit, um diese Analyse einfach umzusetzen.

📚

Was ist eine Konfusionsmatrix?

Eine Konfusionsmatrix ist eine Tabelle, die vorhergesagte Labels mit den tatsächlichen Labels eines Klassifikationsmodells vergleicht. Für binäre Klassifikation ist sie ein 2x2-Raster:

Vorhergesagt PositivVorhergesagt Negativ
Tatsächlich PositivTrue Positive (TP)False Negative (FN)
Tatsächlich NegativFalse Positive (FP)True Negative (TN)

Jede Zelle zählt die Anzahl der Samples, die in diese Kategorie fallen:

  • True Positive (TP): Modell sagt positiv voraus, und es ist tatsächlich positiv. Korrekt.
  • True Negative (TN): Modell sagt negativ voraus, und es ist tatsächlich negativ. Korrekt.
  • False Positive (FP): Modell sagt positiv voraus, aber es ist tatsächlich negativ. Fehler 1. Art (Type I).
  • False Negative (FN): Modell sagt negativ voraus, aber es ist tatsächlich positiv. Fehler 2. Art (Type II).

Grundlegende Konfusionsmatrix mit Sklearn

from sklearn.metrics import confusion_matrix
import numpy as np
 
# Actual and predicted labels
y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1]
 
cm = confusion_matrix(y_true, y_pred)
print(cm)
# [[5 1]
#  [2 7]]

So liest du die Ausgabe: sklearn ordnet die Matrix so an, dass Zeile 0 = tatsächlich negativ und Zeile 1 = tatsächlich positiv ist.

Predicted 0Predicted 1
Actual 0TN = 5FP = 1
Actual 1FN = 2TP = 7

Das Modell hat also 5 Negative und 7 Positive korrekt identifiziert, dabei jedoch 1 False Positive und 2 False Negative Fehler gemacht.

Einzelwerte extrahieren

from sklearn.metrics import confusion_matrix
 
y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1]
 
cm = confusion_matrix(y_true, y_pred)
tn, fp, fn, tp = cm.ravel()
 
print(f"True Negatives:  {tn}")
print(f"False Positives: {fp}")
print(f"False Negatives: {fn}")
print(f"True Positives:  {tp}")
# True Negatives:  5
# False Positives: 1
# False Negatives: 2
# True Positives:  7

Precision, Recall, F1-Score und Accuracy

Diese Metriken werden direkt aus der Konfusionsmatrix abgeleitet:

MetricFormulaWhat It Answers
Accuracy(TP + TN) / (TP + TN + FP + FN)Von allen Vorhersagen: Wie viele waren korrekt?
PrecisionTP / (TP + FP)Von den vorhergesagten Positiven: Wie viele waren tatsächlich positiv?
Recall (Sensitivity)TP / (TP + FN)Von den tatsächlichen Positiven: Wie viele haben wir erkannt?
SpecificityTN / (TN + FP)Von den tatsächlichen Negativen: Wie viele haben wir korrekt erkannt?
F1-Score2 * (Precision * Recall) / (Precision + Recall)Harmonisches Mittel aus Precision und Recall
from sklearn.metrics import (
    accuracy_score, precision_score, recall_score, f1_score
)
 
y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1]
 
print(f"Accuracy:  {accuracy_score(y_true, y_pred):.4f}")
print(f"Precision: {precision_score(y_true, y_pred):.4f}")
print(f"Recall:    {recall_score(y_true, y_pred):.4f}")
print(f"F1-Score:  {f1_score(y_true, y_pred):.4f}")
# Accuracy:  0.8000
# Precision: 0.8750
# Recall:    0.7778
# F1-Score:  0.8235

Wann Precision vs. Recall priorisieren?

ScenarioPrioritizeWhy
SpamerkennungPrecisionFalse Positives (legitime E-Mail als Spam) nerven Nutzer
Krankheits-ScreeningRecallFalse Negatives (übersehene Krankheit) sind gefährlich
BetrugserkennungRecallBetrug zu übersehen ist teurer als False Alarms zu prüfen
Suchmaschinen-ErgebnissePrecisionIrrelevante Ergebnisse verschlechtern die User Experience
Defekterkennung in der FertigungRecallDefekte Produkte bei Kunden sind kostspielig
Content-EmpfehlungenPrecisionIrrelevante Empfehlungen reduzieren Engagement

Classification Report

Sklearns classification_report berechnet Precision, Recall, F1-Score und Support (Anzahl tatsächlicher Vorkommen) pro Klasse in einem Aufruf:

from sklearn.metrics import classification_report
 
y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1]
 
print(classification_report(y_true, y_pred, target_names=['Negative', 'Positive']))

Output:

              precision    recall  f1-score   support

    Negative       0.71      0.83      0.77         6
    Positive       0.88      0.78      0.82         9

    accuracy                           0.80        15
   macro avg       0.80      0.81      0.80        15
weighted avg       0.81      0.80      0.80        15
  • macro avg: Ungewichtetes Mittel über die Klassen. Behandelt alle Klassen gleich.
  • weighted avg: Mittelwert gewichtet nach Support. Berücksichtigt Class Imbalance.
  • support: Anzahl der tatsächlichen Samples pro Klasse.

Konfusionsmatrix visualisieren

Mit ConfusionMatrixDisplay

from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt
 
# Load and split data
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    data.data, data.target, test_size=0.2, random_state=42
)
 
# Train model
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
 
# Plot confusion matrix
cm = confusion_matrix(y_test, y_pred)
disp = ConfusionMatrixDisplay(
    confusion_matrix=cm,
    display_labels=data.target_names
)
disp.plot(cmap='Blues')
plt.title('Breast Cancer Classification')
plt.tight_layout()
plt.savefig('confusion_matrix.png', dpi=150)
plt.show()

Mit Seaborn Heatmap

Für mehr Anpassungsmöglichkeiten nutze seaborn direkt:

from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
 
# Load, split, train
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    data.data, data.target, test_size=0.2, random_state=42
)
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
 
# Create confusion matrix
cm = confusion_matrix(y_test, y_pred)
 
# Plot with seaborn
plt.figure(figsize=(8, 6))
sns.heatmap(
    cm,
    annot=True,
    fmt='d',
    cmap='Blues',
    xticklabels=data.target_names,
    yticklabels=data.target_names,
    square=True,
    linewidths=0.5
)
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
plt.title('Confusion Matrix - Breast Cancer Classification')
plt.tight_layout()
plt.savefig('confusion_matrix_seaborn.png', dpi=150)
plt.show()

Normalisierte Konfusionsmatrix

Rohzählungen können irreführend sein, wenn Klassen unterschiedlich groß sind. Normalisierung zeigt stattdessen Anteile:

from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt
 
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    data.data, data.target, test_size=0.2, random_state=42
)
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
 
# Normalized confusion matrix (by true labels)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
 
# Raw counts
ConfusionMatrixDisplay.from_predictions(
    y_test, y_pred,
    display_labels=data.target_names,
    cmap='Blues',
    ax=axes[0]
)
axes[0].set_title('Raw Counts')
 
# Normalized (rows sum to 1)
ConfusionMatrixDisplay.from_predictions(
    y_test, y_pred,
    display_labels=data.target_names,
    normalize='true',
    cmap='Blues',
    values_format='.2%',
    ax=axes[1]
)
axes[1].set_title('Normalized by True Label')
 
plt.tight_layout()
plt.savefig('confusion_matrix_normalized.png', dpi=150)
plt.show()

Der Parameter normalize akzeptiert drei Optionen:

ValueNormalizationUse Case
'true'Zeilen summieren sich zu 1 (geteilt durch tatsächliche Klassenanzahl)Recall pro Klasse sehen
'pred'Spalten summieren sich zu 1 (geteilt durch vorhergesagte Klassenanzahl)Precision pro Klasse sehen
'all'Alle Zellen summieren sich zu 1 (geteilt durch Gesamtanzahl)Gesamtverteilung sehen

Multi-Class-Konfusionsmatrix

Die Konfusionsmatrix lässt sich natürlich auf mehr als zwei Klassen erweitern. Jede Zeile entspricht einer tatsächlichen Klasse, jede Spalte einer vorhergesagten Klasse:

from sklearn.metrics import confusion_matrix, classification_report, ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
 
# Load iris dataset (3 classes)
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
    iris.data, iris.target, test_size=0.3, random_state=42
)
 
# Train and predict
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
 
# Confusion matrix
cm = confusion_matrix(y_test, y_pred)
print("Confusion Matrix:")
print(cm)
 
# Classification report
print("\nClassification Report:")
print(classification_report(
    y_test, y_pred,
    target_names=iris.target_names
))
 
# Visualize
disp = ConfusionMatrixDisplay(
    confusion_matrix=cm,
    display_labels=iris.target_names
)
disp.plot(cmap='Blues')
plt.title('Iris Classification - 3 Classes')
plt.tight_layout()
plt.savefig('multi_class_confusion_matrix.png', dpi=150)
plt.show()

Multi-Class-Averaging-Strategien

Beim Berechnen von Precision, Recall und F1 für Multi-Class-Probleme musst du eine Averaging-Methode wählen:

from sklearn.metrics import precision_score, recall_score, f1_score
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
 
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
    iris.data, iris.target, test_size=0.3, random_state=42
)
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
 
for avg in ['micro', 'macro', 'weighted']:
    p = precision_score(y_test, y_pred, average=avg)
    r = recall_score(y_test, y_pred, average=avg)
    f1 = f1_score(y_test, y_pred, average=avg)
    print(f"{avg:8s} -- Precision: {p:.4f}, Recall: {r:.4f}, F1: {f1:.4f}")
AverageMethodBest For
microGesamt-TP, FP, FN über alle KlassenWenn Class Imbalance wichtig ist
macroUngewichtetes Mittel pro KlasseWenn alle Klassen gleich wichtig sind
weightedGewichtetes Mittel nach SupportStandardwahl bei imbalancierten Datensätzen

Komplettes Beispiel: End-to-End-Evaluation einer Klassifikation

from sklearn.metrics import (
    confusion_matrix, classification_report, ConfusionMatrixDisplay,
    accuracy_score, precision_score, recall_score, f1_score, roc_auc_score
)
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt
import numpy as np
 
# Load data
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    data.data, data.target, test_size=0.2, random_state=42, stratify=data.target
)
 
# Build pipeline
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('model', GradientBoostingClassifier(
        n_estimators=200, max_depth=3, random_state=42
    ))
])
 
# Train
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
y_prob = pipeline.predict_proba(X_test)[:, 1]
 
# Confusion matrix
cm = confusion_matrix(y_test, y_pred)
tn, fp, fn, tp = cm.ravel()
 
print("=" * 50)
print("MODEL EVALUATION REPORT")
print("=" * 50)
print(f"\nConfusion Matrix:")
print(f"  TP={tp}, FP={fp}")
print(f"  FN={fn}, TN={tn}")
print(f"\nAccuracy:  {accuracy_score(y_test, y_pred):.4f}")
print(f"Precision: {precision_score(y_test, y_pred):.4f}")
print(f"Recall:    {recall_score(y_test, y_pred):.4f}")
print(f"F1-Score:  {f1_score(y_test, y_pred):.4f}")
print(f"ROC-AUC:   {roc_auc_score(y_test, y_prob):.4f}")
print(f"\nDetailed Report:")
print(classification_report(y_test, y_pred, target_names=data.target_names))
 
# Visualize
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
ConfusionMatrixDisplay.from_predictions(
    y_test, y_pred, display_labels=data.target_names,
    cmap='Blues', ax=axes[0]
)
axes[0].set_title('Raw Counts')
 
ConfusionMatrixDisplay.from_predictions(
    y_test, y_pred, display_labels=data.target_names,
    normalize='true', values_format='.1%', cmap='Blues', ax=axes[1]
)
axes[1].set_title('Normalized')
plt.tight_layout()
plt.savefig('full_evaluation.png', dpi=150)
plt.show()

Classification-Ergebnisse mit PyGWalker erkunden

Nachdem du deine Konfusionsmatrix erstellt hast, kannst du tiefer in Fehlklassifikationen eintauchen, indem du die Rohdaten interaktiv untersuchst. PyGWalker (opens in a new tab) verwandelt deine Prediction-Ergebnisse in eine Drag-and-drop-Oberfläche für Visual Analytics in Jupyter:

import pandas as pd
import pygwalker as pyg
 
# Build results DataFrame with features and predictions
results = pd.DataFrame(X_test, columns=data.feature_names)
results['actual'] = y_test
results['predicted'] = y_pred
results['correct'] = y_test == y_pred
results['confidence'] = y_prob
 
# Launch interactive exploration
walker = pyg.walk(results)

Filtere nach falsch klassifizierten Samples, vergleiche Feature-Verteilungen zwischen TP/FP/FN/TN-Gruppen und identifiziere Muster, die erklären, wo das Modell Schwierigkeiten hat.

Um Klassifikations-Experimente in Jupyter iterativ zu verbessern – Thresholds anpassen, verschiedene Modelle testen oder Feature-Kombinationen explorieren – bietet RunCell (opens in a new tab) einen AI agent, der den Experimentier-Loop beschleunigt.

FAQ

Was ist eine Konfusionsmatrix in sklearn?

Eine Konfusionsmatrix ist eine Tabelle, die die Anzahl korrekter und inkorrekter Vorhersagen pro Klasse zeigt. In sklearn gibt confusion_matrix(y_true, y_pred) ein 2D-numpy-Array zurück, bei dem die Zeilen die tatsächlichen Klassen und die Spalten die vorhergesagten Klassen darstellen. Bei binärer Klassifikation zeigt sie True Positives, True Negatives, False Positives und False Negatives.

Wie lese ich eine Konfusionsmatrix?

In der Konfusionsmatrix von sklearn sind die Zeilen die tatsächlichen Labels und die Spalten die vorhergesagten Labels. Bei binärer Klassifikation: oben links True Negatives (TN), oben rechts False Positives (FP), unten links False Negatives (FN) und unten rechts True Positives (TP). Die Diagonaleinträge sind die korrekten Vorhersagen.

Was ist der Unterschied zwischen Precision und Recall?

Precision misst, wie viele der vorhergesagten Positiven tatsächlich positiv sind (TP / (TP + FP)). Recall misst, wie viele der tatsächlichen Positiven das Modell gefunden hat (TP / (TP + FN)). Precision beantwortet „Wenn das Modell positiv sagt, wie oft hat es recht?“, während Recall beantwortet „Von allen tatsächlichen Positiven: Wie viele hat das Modell gefunden?“

Wann sollte ich F1-score statt Accuracy verwenden?

Nutze den F1-Score, wenn deine Klassen im Ungleichgewicht sind. Wenn 95% der Samples negativ sind, erreicht ein Modell, das immer negativ vorhersagt, 95% Accuracy, aber 0% Recall auf der positiven Klasse. Der F1-Score ist das harmonische Mittel aus Precision und Recall und bestraft Modelle, die eine der beiden Kennzahlen stark zugunsten der anderen opfern.

Wie plotte ich eine Konfusionsmatrix in Python?

Nutze ConfusionMatrixDisplay.from_predictions(y_true, y_pred) als schnellste Methode. Für mehr Anpassung kannst du die Matrix mit confusion_matrix() berechnen und mit seaborn.heatmap() visualisieren. Beide Ansätze unterstützen normalisierte Matrizen, eigene Color Maps und Klassenlabels.

Was bewirkt normalize='true' in ConfusionMatrixDisplay?

normalize='true' teilt jede Zeile durch die Gesamtzahl der tatsächlichen Samples dieser Klasse, sodass jede Zeile zu 1 summiert. Dadurch wird der Recall pro Klasse als Prozentwert sichtbar. Nutze normalize='pred', um Precision pro Klasse zu sehen, oder normalize='all' für den Gesamtanteil.

Fazit

Die Konfusionsmatrix ist die Grundlage für die Evaluation von Klassifikationsmodellen. Accuracy allein ist nicht ausreichend – du musst die konkreten Fehlerarten sehen, die dein Modell macht. Nutze confusion_matrix und classification_report aus sklearn, um das vollständige Bild zu erhalten, visualisiere mit ConfusionMatrixDisplay oder seaborn-Heatmaps für Präsentationen und Reports, und normalisiere, wenn sich die Klassengrößen unterscheiden. Wähle deine primäre Metrik anhand der Business-Kosten jeder Fehlerart: Precision, wenn False Positives teuer sind, Recall, wenn False Negatives gefährlich sind, und F1-Score, wenn du ein ausgewogenes Maß brauchst.

📚