September 12, 2026

Wahrscheinlichkeiten kalibrieren

Viele Machine-Learning-Modelle (wie Random Forests oder SVMs) optimieren auf Trennschärfe (ROC-AUC, Accuracy), liefern aber keine echten Wahrscheinlichkeiten. Ein Score von 0.8 bedeutet hier oft nicht, dass ein Ereignis zu 80 % eintritt. Downstream-Systeme und Fachbereiche benötigen meist verlässliche Wahrscheinlichkeiten zur Berechnung von Erwartungswerten (Expected Values). Um dies zu ermöglichen müssen die Scores daher kalibriert werden.

Die mathematischen Grundlagen

Ein Modell gilt als perfekt kalibriert, wenn der vorhergesagte Wahrscheinlichkeitswert p der tatsächlichen relativen Häufigkeit der positiven Klasse entspricht. Formal ausgedrückt:

\(P(Y=1 | \hat{p} = p) = p\)

Das bedeutet: Wenn wir alle Vorhersagen sammeln, bei denen unser Modell eine Wahrscheinlichkeit von $\hat{p} = 0.7$ ausgibt, sollten in dieser Gruppe exakt 70% der Labels tatsächlich positiv (Y=1) sein.

Bewertung der Kalibierung

Es gibt zwei Standardmetriken, um die Kalibrierung eines Modells zu bewerten.

  1. Brier Score: Im Grunde der Mean Squared Error (MSE) für Wahrscheinlichkeiten. Ein niedrigerer Wert ist besser.
  2. Expected Calibration Error (ECE): Die Vorhersagen werden in Bins (z. B. 10 Intervalle) eingeteilt. Für jedes Bin vergleichen wir die durchschnittliche vorhergesagte Wahrscheinlichkeit mit der tatsächlichen Accuracy im Bin. Der ECE ist der gewichtete Durchschnitt dieser Differenzen.

Das Reliability Diagram (Kalibrierungskurve)

In einem sogenannten Reliability Diagram plotten wir die tatsächliche Häufigkeit gegen die vorhergesagte Wahrscheinlichkeit. Es ist das wichtigste visuelle Werkzeug, um die Kalibrierung eines Modells zu bewerten und Fehler in der Wahrscheinlichkeitsausgabe zu diagnostizieren.

Die vom Modell vorhergesagten Wahrscheinlichkeiten (Scores) werden in Bins (Intervalle) unterteilt. Für jedes Bin berechnet man die durchschnittliche vorhergesagte Wahrscheinlichkeit (X-Achse). Dem gegenüber stellt man die tatsächliche relative Häufigkeit der positiven Klasse in diesem Bin (Y-Achse).

Bei einem perfekt kalibriertes Modell liegt die Kurve exakt auf der Diagonalen (Ursprungsgerade). Wenn das Modell in einem Bin im Schnitt 70 % vorhersagt, sind auch exakt 70 % der Datensätze in diesem Bin positiv.

Liegt die empirische Kurve unter der Diagonalen überschätzt das Modell. Umgekehrt, wenn die Kurve über der Diagonalen liegt, unterschätzt das Modell.

Praktische Umsetzung

Umgesetzt wird die Kalibrierung, indem ein zweites Modell (der Kalibrator) auf die Vorhersagen des Basismodells trainiert wird. Es gibt zwei gängige Methoden.

Platt Scaling (Logistische Kalibrierung)

Hier fitten wir eine einfache logistische Regression auf die Ausgabe des Basismodells. Dazu nimmt an die unkalibrierten Vorhersagen des Modells und steckt sie in eine klassische Sigmoid-Funktion mit zwei Parametern, A und B. Die kalibrierte Wahrscheinlichkeit berechnet sich als:

\(\hat{q}_i = \frac{1}{1+exp(-(A \cdot \hat{p}_i +B))}\)

Das Kalibratormodell sucht (meist per Maximum Likelihood) nach den idealen Werten für A und B, so dass die Sigmoid-Kurve den Brier Score minimiert.

Das funktioniert hervorragend bei kleinen Datensätzen.Der Nachteil ist, dass das Modell eine spezifische S-Kurven-Form der Verzerrung annimmt. Platt Scaling zwingt die Kalibrierung in die Form eines „S“. Es geht davon aus, dass die Fehler des Basismodells einer bestimmten Struktur folgen: Die mittleren Wahrscheinlichkeiten sind vielleicht in Ordnung, aber zu den Rändern hin (nahe 0 und 1) verschätzt sich das Modell systematisch.

Isotonic Regression

Dies ist ein nicht-parametrischer Ansatz, der eine monoton steigende Treppenfunktion fittet. Die Methode minimiert den quadratischen Fehler zwischen den kalibrierten Wahrscheinlichkeiten und den echten Labels (0 oder 1):

\(\sum_i(y_i – \hat{q}_i)^2 \)

Der Algorithmus sortiert zuerst alle Vorhersagen des Basismodells. Dann fasst er angrenzende Vorhersagen in Gruppen („Blöcke“ oder „Stufen“) zusammen, bis die Bedingung erfüllt ist, dass jede Stufe im Durchschnitt eine höhere Positiv-Rate hat als die vorherige. Das Resultat ist eine Treppenfunktion (Step Function). Jede „Stufe“ der Treppe repräsentiert ein Bin, in dem das Modell eine konstante kalibrierte Wahrscheinlichkeit ausgibt.

Der Ansatz ist flexibler als Platt Scaling und kann nahezu jede Art von monotoner Verzerrung ausgleichen. Allerdings benötigt der Ansatz deutlich mehr Daten, sonst neigt er stark zum Overfitting. Sie lernt das Rauschen (Noise) mit. Außerdem verlierst Du Auflösung (Resolution), weil viele unterschiedliche, feine Scores aus dem Basismodell auf dieselbe „Treppenstufe“ gezogen werden und denselben kalibrierten Wert erhalten.

Code Beispiel

In Python ist das Ganze mit Scikit-Learn in wenigen Zeilen erledigt. Wichtig: Man nutzt immer ein separates Holdout-Set für die Kalibrierung, um Data Leakage zu vermeiden!

from sklearn.calibration import CalibratedClassifierCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import brier_score_loss

# 1. Daten generieren (5000 Samples)
X, y = make_classification(n_samples=5000, n_classes=2, random_state=42)

# 3-Way-Split: 60% Train, 20% Calib, 20% Test
# X_temp bekommt 2000 Samples
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.4, random_state=42)
# X_calib und X_test bekommen jeweils 1000 Samples
X_calib, X_test, y_calib, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)

# 2. Basis-Modell auf X_train trainieren
rf = RandomForestClassifier(n_estimators=50, random_state=42)
rf.fit(X_train, y_train)

# Wahrscheinlichkeiten des unkalibrierten Modells generieren (Länge: 1000)
probs_uncalibrated = rf.predict_proba(X_test)[:, 1]

# 3. Kalibrierung auf X_calib durchführen
# "isotonic" für isotone Regression, "sigmoid" für Platt Scaling
calibrated_rf = CalibratedClassifierCV(estimator=rf, cv=5, method='isotonic')
calibrated_rf.fit(X_calib, y_calib)

# Kalibrierte Wahrscheinlichkeiten generieren (Länge: 1000)
probs_calibrated = calibrated_rf.predict_proba(X_test)[:, 1]

# 4. Evaluierung auf y_test (Länge: 1000)
print(f"Brier Score (Unkalibriert): {brier_score_loss(y_test, probs_uncalibrated):.4f}")
print(f"Brier Score (Kalibriert):   {brier_score_loss(y_test, probs_calibrated):.4f}")