Zugverspätung, 30 Minuten im Voraus.

MAE 4,80 min mittlerer Prognosefehler · 30-min-Horizont · 850k+ gemessene Halte

Eigener Collector, eigenes DWH, eigenes Modell — end-to-end, zeitehrlich, Bugs offengelegt.

Modell v1.1 · Live-Daten Stand 06.08.2026, 14:04 UTC
4,80 minMAE Verspätung (30-min-Horizont)
0,84AUC „verspätet > 6 min"
850k+gemessene Abfahrten, selbst gesammelt
90,1 %Quantil-Coverage q90 (Soll 90 %)
01

Model Card

Testset, ehrlich · ml/eval.json

Ein Gradient-Boosting-Modell sagt die Abfahrtsverspätung 30 Minuten im Voraus auf 4,80 min mittleren Fehler genau — knapp die Hälfte der naiven Baseline (8,80 min). „Wird dieser Zug > 6 min verspätet?" trifft es mit AUC 0,84. Regionalverkehr sehr gut, Nacht- und Fernverkehr schwächer — und es sagt ehrlich, warum.

Steckbrief
AufgabeRegression delay_dep · Klassifikation „verspätet > 6 min" & „Ausfall"
HorizontT = geplante Abfahrt − 30 min, zeitehrlich (nur Features, die zu T real bekannt waren)
ModellHistGradientBoosting, getrennte Köpfe, isotonische Kalibrierung
Daten766k Trainingszeilen, 72 Bahnhöfe · Test = letzte 5 Tage (85.546 Abfahrten)
ValidierungRolling-Origin-Backtest, 8 Folds à 5 Tage: MAE 4,54 ± 0,98
Kern-Metriken (Testset)
MetrikModellBaselineLesart
MAE Verspätung4,80 min8,80 min~45 % besser als „rate den Schnitt"
Median-Fehler1,64 min7,36 minDie Hälfte aller Züge auf < 1,7 min genau
AUC „verspätet > 6 min"0,843Solider Frühwarn-Klassifikator
Recall @ Precision 0,579,3 %Jede 2. Warnung stimmt → 4 von 5 Verspätungen gefangen

Was treibt die Vorhersage?

Permutation-Importance, Top 8 · der eigene Zuglauf dominiert

Zuletzt bekannte Verspätung (selber Zug) 3,33 Bahnhof (eva) 0,23 Zuggattung 0,15 IRIS-Eigenprognose 0,13 Gleis-Taktlücke 0,12 Linien-Mittel, 60 min 0,08 Max. Laufverspätung 0,07 Bahnhofs-Verspätungsquote, 60 min 0,06

Ablation — ΔMAE je Feature-Gruppe

MAE-Verschlechterung ohne die Gruppe · Kaskade = der Hebel

Zuglauf-Kaskade +1,26 Rollende Statistik +0,07 Vorgänger am Gleis +0,05 Historische Priors +0,02 Bahnhofs-Meldungen +0,01 Kalender ≈0

In einem Satz: der beste Prädiktor für eine verspätete Abfahrt ist eine verspätete Ankunft. Das wichtigste Feature — die zuletzt bekannte Verspätung desselben Zuges an einem früheren Halt — ist rund zehnmal so wichtig wie das nächstbeste.

Kalibrierung — die Wahrscheinlichkeiten stimmen

Quantil-Coverage (Regressor, Pinball-Loss)
QuantilSollIst
q50 (Median)50 %53,0 %
q8080 %80,8 %
q9090 %90,1 %

Sagt das q90-Modell „höchstens 12 min", stimmt das in 90,1 % der Fälle. Damit wird aus der Prognose eine Antwort auf die eigentliche Frage am Bahnsteig — „Krieg ich meinen Anschluss?": RE1 nach Köln, 8 min Umsteigezeit → Median +2 min, q90 +7 min → „~88 % Chance auf den Anschluss." Eine Zahl, deren Kalibrierung nachgeprüft ist.

Wo das Modell gut ist — und wo nicht Per-Zugtyp-Split
SegmentBeispieleMAEUrteil
RegionalverkehrRB 3,19 · S 3,26 · RE 3,54~3 minSehr gut — dichtes Netz, viel Kaskaden-Signal
Fernverkehr TagICE 8,73 · IC 8,66~9 minMittel — lange Läufe, Fehler akkumuliert
Nacht / InternationalNJ 27,2 · EC 24,520–27 minSchwach — dünne Daten, extreme Ausreißer

Das ist kein Bug, das ist die Datenlage. Große Verspätungen entstehen aus Kaskaden — sichtbar nur, wenn der auslösende Zug durch beobachtete Bahnhöfe fährt. Nachtzüge verlassen das beobachtete Netz, Regionalzüge bleiben drin. Der Hebel ist deshalb nicht mehr Tuning, sondern Daten-Coverage: Upstream-Halte dichter beobachten.

Limitationen ehrlich, ungeschönt

· 30 Minuten ist die ehrliche Grenze — kürzer bringt kaum Signal, weil IRIS Störungsmeldungen zu spät rausgibt (belegt, siehe Bugs).
· Ausfall-Vorhersage bei hoher Präzision schwach (Recall@P0,5 nur 13 %). Noch nicht produktreif.
· Sondereffekte wie die Generalsanierung Wuppertal–Köln (wiedereröffnet 11.07.) verschieben Muster; Retrain mit Regime-Feature folgt im August.
· Kein Kausalmodell. Korrelationen aus Vergangenheitsdaten, unbekannte Muster extrapoliert es blind.

Reproduzierbar: ml/eval.json, ml/backtest.json, ml/ablation.json im Repo.

03

Das Netz, live.

aus der eigenen Pipeline, laufend aktualisiert

Pünktlichkeit, letzte 30 Tage

Stand 06.08.2026, 14:04 UTC
65%70%75%80%11.07.18.07.25.07.01.08.

Linie: Anteil Halte unter 6 min Abfahrts-Verspätung. Balken: gemessene Halte. Quelle: DB IRIS-TTS, minütlich abgefragt.

935.087 Halte / 30 Tage 19.788 Halte / Tag 75 Stationen 72 % pünktlich < 6 min (7 Tage)

Verspätung nach Tageszeit

Anteil Halte ≥ 6 min, letzte 30 Tage
10%20%30%000306091215182134%

Die Rushhour ab 16 Uhr ist das unzuverlässigste Fenster; am pünktlichsten ist der frühe Morgen.

Verspätungsradar — der Vortag im Zeitraffer

täglich neu gerendert
Animierte Karte: mittlere Verspätung je Station im Tagesverlauf

Wie ein Regenradar, nur für Verspätungen: Farbe = mittlere Verspätung, Punktgröße = Zugdichte. MP4.

Butterfly-Effekt des Tages

größte Folgeverspätung im eigenen Zuglauf
Kaskaden-Verlauf: Verspätung der Top-3-Züge entlang ihrer Halte

Welcher Zug hat gestern die größte Folgeverspätung ausgelöst? Konservativ attribuiert: nur innerhalb desselben Zuglaufs.

04

Befunde

aus 5 Analyse-Spikes, Reports im Repo
29,7 %
der verspäteten Halte (≥ 6 min) bekommen nie eine Disruption-Message. Die Bahn weiß es — sagt es aber nicht.
22 min
vor dem Cancel-Flag taucht im Schnitt die Erklärungs-Message auf — ein Frühwarnsignal. Explizit storniert werden nur 1,7 % der Ausfälle.
~22,5 %
der knappen Anschlüsse (5–30 min Puffer) platzen — 2 Mio ausgewertete Umsteige-Paare an 63 Hubs.
05

Drei Bugs, die uns klüger gemacht haben.

die zu guten Zahlen sind die interessanten
Das Modell, das zu gut war Temporal Leakage
Symptom
AUC 0,86 für Verspätung, 0,85 für Ausfall — brillant. Zu brillant.
Diagnose
Die Features aggregierten über den gesamten Lebenszyklus einer Fahrt — inklusive Information, die zum Vorhersage-Zeitpunkt noch nicht existierte. 92 % aller Störungsmeldungen tauchen erst nach der geplanten Abfahrt auf. Zeitehrlich gerechnet: AUC 0,61, Ausfall 0,49 — schlechter als Münzwurf.
Fix
Umbau der Feature-Pipeline auf Append-only-Tabellen mit echten Timestamps.
Lesson
Ein AUC-Sprung > 0,2 ist ein Rauchmelder, keine Erfolgsmeldung. Die 0,61 hinzuschreiben statt die 0,86 zu behalten, war die eigentliche Leistung.
Der doppelte <m> die verdoppelte Realität
Symptom
Der times_seen-Zähler war rund doppelt so hoch wie plausibel; reappeared häufiger als appeared — unmöglich.
Diagnose
IRIS liefert jede Meldung in beiden XML-Knoten <ar> und <dp>. Der Collector zählte doppelt.
Fix
4-Zeilen-Dedup über die Message-ID; Forward-Cutoff ab Fix-Zeitpunkt.
Lesson
Sanity-Checks auf Aggregaten fangen, was Code-Review übersieht.
Das Unwetter, das keins war Baseline-Disziplin
Symptom
Bei Störungscode d/45 („Unwetter") zeigte das Wetter in 95 % der Fälle klaren Himmel. Erst-These: „Die Bahn labelt Unwetter falsch."
Diagnose
Baseline-Check: auch ohne d/45 sind ~93 % klarer Himmel. Lift über Baseline: fast null — d/45 läuft meist als Co-Code.
Lesson
Ein Befund ohne Baseline ist kein Befund. Der klickbare Take wäre falsch gewesen; die Kontrollgruppe kostet 20 Minuten.
06

Eigene Daten, eigener Unterbau.

Die Bahn veröffentlicht Monats-Durchschnitte; eine öffentliche, minutengenaue Historie gibt es nicht. Also bauen wir sie selbst: Ein stdlib-only-Python-Daemon pollt das IRIS-Backend im Minutentakt, reichert um Wetter und DELFI-Fahrplan an und schreibt in eine SQLite-Datei — seit 22. März 2026 ohne Datenlücke. Der Clou: Append-only-History-Tabellen neben den Snapshots. Erst dadurch lässt sich zeitehrlich trainieren — man rekonstruiert, was zu einem Zeitpunkt bekannt war, statt aus der Zukunft zu lesen.

Collector auf AWS, Heimserver für Archiv + Training. Watermark-Replikation, 3-2-1-Backup, 66 Tests.

07

Mehr

RailCast entsteht in Zusammenarbeit von Pet (Richtung, Domain-Wissen, Entscheidungen) und zwei Claude-Agents auf getrennten Hosts — offengelegt in PROCESS.md. Daten aus öffentlicher API, Analysen in SQL/Python, unabhängig reproduzierbar.