·  METHODEN-NOTIZEN
PREDICTIVE ANALYTICS · MODELLGÜTE · R

Decision Curve Analysis in R: wann ein Modell eine Entscheidung wirklich verbessert

Methoden-Notizen. Verfahren, die eine Entscheidung tragen, mit der Prüfgröße, die dazugehört.
10. September 2026 · ~10 Min · Nico Schäfer
ZIELSTELLUNG UND ERGEBNIS

Die AUC misst, ob ein Modell Fälle richtig sortiert. Sie misst nicht, ob eine Entscheidung auf ihrer Grundlage besser wird. Der Net Benefit misst das, weil er Treffer und Fehlalarme über genau das Kostenverhältnis verrechnet, das im konkreten Fall gilt. Unten stehen zwei Modelle mit identischer AUC bis auf die letzte Stelle; bei niedriger Entscheidungsschwelle ist eines davon meistens schlechter als die modellfreie Regel „alle warten". Rund zwanzig Zeilen R zeigen den Unterschied.

Das Praxisproblem

Ein Vorhersagemodell ist fertig, die AUC liegt bei 0,78. Dann kommt die Frage, die das Modell erst zu einem Werkzeug macht: Ab welchem Wert handeln wir?

Ab da hilft die AUC nicht mehr. Sie ist eine Rangmaßzahl und sagt, wie oft ein zufällig gezogener Ausfall einen höheren Score bekommt als ein zufällig gezogener Nicht-Ausfall. Über die Frage, ob es sich lohnt, bei einem geschätzten Risiko von acht Prozent eine Anlage vorbeugend zu warten, sagt sie nichts. Sie kann es auch nicht sagen, weil in dieser Frage etwas steckt, das nicht in den Daten liegt: was ein Fehler kostet, und zwar welcher.

Nancy Cook hat das 2007 in Circulation an einem Beispiel gezeigt, das seither Standard ist: In der Women's Health Study hoben LDL-, HDL- und Gesamtcholesterin die c-Statistik jeweils nur um 0,01. Wer sein Modell nach der AUC baut, wirft etablierte Risikofaktoren heraus. Falsch ist das Maß deshalb nicht. Es beantwortet nur eine andere Frage als die, die auf dem Tisch liegt.

Die Decision Curve Analysis (deutsch gelegentlich Entscheidungskurvenanalyse) von Andrew Vickers und Elena Elkin schließt genau diese Lücke.

Die Idee in einem Satz

Man legt fest, ab welcher geschätzten Wahrscheinlichkeit man handeln würde, und diese Schwelle ist das Kostenverhältnis.

Wenn ich eine Anlage vorbeugend warte, sobald ihr Ausfallrisiko fünf Prozent übersteigt, dann sage ich damit implizit: Ein Ausfall kostet mich neunzehnmal so viel wie eine unnötige Wartung. Denn genau bei diesem Verhältnis wäre ich zwischen beiden Optionen indifferent.

Schwelle p_t0,030,050,100,20
Ausfall kostet das …-fache einer Wartung32,319,09,04,0

Der Net Benefit rechnet mit diesem Wechselkurs:

NB(p_t) = TP/n − (FP/n) × p_t/(1 − p_t)

Er zählt richtig gefundene Fälle je Beobachtung, abzüglich der Fehlalarme zu ihrem Kostengewicht. Und weil eine Zahl ohne Vergleich nichts wert ist, kommen zwei Referenzstrategien dazu, die kein Modell brauchen: alle behandeln und keinen behandeln. Nützlich ist ein Modell dort, wo es über beiden Referenzstrategien liegt, und die Frage ist, ob das im ganzen Bereich plausibler Schwellen gilt.

Der Code

4.000 Anlagen, drei Merkmale, ein logistisches Risikomodell. Ausfälle sind selten (Prävalenz 0,136), was dem Normalfall im Betrieb entspricht. Das Modell wird auf der einen Hälfte geschätzt und auf der anderen ausgewertet; ohne diese Trennung misst man das Rauschen mit.

dca_wartung.R
library(dplyr)
library(tidyr)
set.seed(2026)

N <- 4000
dat <- tibble(x1 = rnorm(N), x2 = rnorm(N), x3 = rbinom(N, 1, 0.35)) |>
  mutate(p_wahr = plogis(-2.6 + 0.9 * x1 + 0.7 * x2 + 0.8 * x3),
         y      = rbinom(N, 1, p_wahr))

idx   <- sample(seq_len(N), N / 2)
train <- dat |> slice(idx)
test  <- dat |> slice(-idx)

fit_A <- glm(y ~ x1 + x2 + x3, data = train, family = binomial)

Und jetzt der Vergleichsfall. Modell B ist Modell A mit anderen Wahrscheinlichkeiten, aber derselben Rangfolge:

test <- test |>
  mutate(pA = predict(fit_A, newdata = test, type = "response"),
         pB = plogis(1.9 * qlogis(pA) + 1.4))   # streng monoton, systematisch zu hoch

Das ist bewusst konstruiert, und zwar um einen Punkt zu isolieren, der sich sonst schwer erzählen lässt: Die AUC ist gegen streng monotone Transformationen invariant. Sie sieht nur die Reihenfolge. Der Net Benefit sieht die Wahrscheinlichkeit, und die vergleicht er mit der Schwelle.

Die Kurve selbst ist ein group_by über die Schwellen:

kurve <- crossing(pt = seq(0.01, 0.40, by = 0.005),
                  test |> select(y, pA, pB)) |>
  group_by(pt) |>
  summarise(
    nb_A   = mean(pA >= pt & y == 1) - mean(pA >= pt & y == 0) * (pt / (1 - pt)),
    nb_B   = mean(pB >= pt & y == 1) - mean(pB >= pt & y == 0) * (pt / (1 - pt)),
    nb_all = mean(y == 1)            - mean(y == 0)            * (pt / (1 - pt)),
    .groups = "drop")          # nb_all = "alle warten", "keinen warten" ist 0

Für den produktiven Einsatz gibt es dcurves (Sjoberg, MSKCC, Version 0.5.1 vom November 2025); das Paket deckt laut Dokumentation auch zensierte Daten, Case-Control-Designs und die Overfit-Korrektur ab. Für das Verständnis ist die Handrechnung besser: Man sieht, wo das Kostenverhältnis einsteigt.

AUC und Kalibrierung sind ebenfalls fünf Zeilen. Die Kalibrierungs-Steigung ist der Koeffizient auf den Logit der Vorhersage; bei einem gut kalibrierten Modell liegt sie bei 1:

guete <- function(daten, score) {
  daten |>
    summarise(
      n1  = sum(y == 1),
      n0  = sum(y == 0),
      auc = (sum(rank({{ score }})[y == 1]) - n1 * (n1 + 1) / 2) / (n1 * n0),
      steigung = coef(glm(y ~ qlogis({{ score }}), family = binomial))[2])
}

test |> guete(pA)
test |> guete(pB)

Das Ergebnis

Ein einzelner Split trägt keine Aussage. Alle folgenden Zahlen stammen aus 200 Läufen mit je neu gezogenem Datensatz und neuem Split, sofern nicht anders vermerkt.

Erstens, die AUC.

Mittelsd
AUC Modell A0,78540,0145
AUC Modell B0,78540,0145

Die maximale absolute Differenz über alle 200 Läufe: 0,00e+00. Nicht klein, sondern null. Nach der meistberichteten Prüfgröße für Vorhersagemodelle sind diese beiden Modelle identisch.

Zweitens, die Kalibrierung (aus dem ersten Lauf, weil die Kennzahlen je Lauf kaum variieren):

mittlere VorhersagebeobachtetKalibrierungs-Steigung
Modell A0,13790,13100,962
Modell B0,15350,13100,506

Drittens, der Net Benefit. Mittel über 200 Läufe:

p_talle wartenModell AModell BDifferenz A − B
0,030,107490,109450,104330,00512 (4,7 % von A)
0,050,088700,095820,091580,00424 (4,4 %)
0,100,038070,069880,068540,00134 (1,9 %)
0,15−0,018510,051880,051690,00019 (0,4 %)
0,20−0,082170,038550,038380,00018 (0,5 %)
0,30−0,236760,021450,018000,00346 (16,1 %)

Net-Benefit-Werte sind schwer zu lesen. Dieselbe Rechnung in einer Einheit, die im Gespräch trägt, sind vermiedene unnötige Wartungen je 1000 Anlagen gegenüber „alle warten", bei gleicher Zahl gefundener Ausfälle, mit dem 5. bis 95. Perzentil über die 200 Läufe:

p_tKostenfaktorModell AModell B
0,0332,3+63,5 [−12,0; +125,0]−102,0 [−272,8; +53,1]
0,0519,0+135,2 [+66,9; +200,8]+54,6 [−50,6; +157,2]
0,109,0+286,2 [+233,0; +340,2]+274,2 [+210,8; +343,1]
0,204,0+482,9 [+438,8; +526,6]+482,2 [+439,8; +524,2]
Vermiedene unnötige Wartungen je 1000 Anlagen über der Schwellenwahrscheinlichkeit, Modell A gegen Modell B vermiedene unnoetige wartungen je 1000 anlagen (gegenueber "alle warten") +400 +200 −200 null-linie: "alle warten" +63,5 −102,0 0.03 0.05 0.10 0.20 schwellenwahrscheinlichkeit p_t modell a (kalibriert, steigung 0.96) modell b (fehlkalibriert, steigung 0.51)
Beide Modelle haben dieselbe AUC. Links, bei niedriger Schwelle, fällt Modell B unter die Null-Linie: Dort ist es schlechter, als alle Anlagen zu warten. Bänder sind das 5. bis 95. Perzentil über 200 Läufe.

Die Perzentile bei p_t = 0,03 überschreiten in beiden Fällen die Null. Die Aussage steht deshalb besser als Häufigkeit: In wie vielen der 200 Läufe ist die Strategie schlechter als „alle warten"?

p_tModell AModell B
0,039 %85 %
0,050 %21 %
0,100 %0 %
0,200 %0 %

Das ist der Befund. Bei p_t = 0,20, wenn ein Ausfall das Vierfache einer Wartung kostet, sind die beiden Modelle nicht zu unterscheiden. Bei p_t = 0,03, wenn ein Ausfall das 32-fache kostet, spart Modell A im Mittel 64 unnötige Wartungen je 1000 Anlagen, während Modell B in 85 von 100 Läufen schlechter abschneidet, als hätte man einfach alle gewartet. Bei identischer AUC.

Wo die Fehlkalibrierung weh tut. Der Unterschied ist bei niedrigen Schwellen groß (4,7 Prozent des Net Benefit bei p_t = 0,03), schrumpft im mittleren Bereich auf unter ein halbes Prozent (p_t = 0,15 und 0,20) und wächst bei hohen Schwellen relativ wieder an, auf 16 Prozent bei p_t = 0,30. Das Letzte ist allerdings ein Anteil an einem kleinen Nenner: Dort liegt der absolute Nutzen beider Modelle nur noch bei rund einem Fünftel des Werts bei p_t = 0,05. Praktisch relevant ist der Bereich links: Wenn ein übersehener Fall teuer ist, entscheidet die Kalibrierung mit.

So nutze ich das produktiv

Die Schwelle wird vorher festgelegt und nicht nachher abgelesen. Vickers nennt das in seinen „Seven Common Errors in Decision Curve Analysis" (2023) als Fehler 5, und es ist der Fehler, der am häufigsten passiert: Man rechnet die Kurve, sucht den Bereich, in dem das eigene Modell gut aussieht, und erklärt ihn zum relevanten. Der Bereich kommt aus dem Fachgespräch, also aus der Frage, was ein Ausfall kostet und was eine Wartung, und nicht aus der Grafik. Ein Nebeneffekt macht die Sache erst nützlich: Die Frage nach dem Kostenverhältnis führt ein Gespräch, das ohne sie nicht stattfindet. In der Praxis kennt der Fachbereich das Verhältnis oft nicht genau, kann aber eine Spanne nennen, und eine Spanne reicht.

Der Schwellenbereich bleibt eng. Fehler 2 auf derselben Liste. Eine Kurve von 0 bis 1 sieht gründlich aus, ist aber Unsinn: Niemand wartet eine Anlage erst bei 80 Prozent Ausfallrisiko vorbeugend. Eingezeichnet wird der Bereich, in dem jemand tatsächlich entscheiden würde.

Kalibrierung wird mitgeprüft und nicht vorausgesetzt. Das Beispiel oben ist konstruiert, das Muster dahinter ist es nicht: Modelle werden auf einer Population geschätzt und auf einer anderen eingesetzt, Prävalenzen verschieben sich, und die Rangfolge bleibt dabei oft brauchbar, während die Wahrscheinlichkeiten wegdriften. Van Calster und Kollegen nennen die Kalibrierung deshalb die Achillesferse der Predictive Analytics. In einer produktiven Pipeline gehören Kalibrierungs-Intercept und -Steigung neben die AUC ins Monitoring, und wenn die Steigung wegläuft, ist der Net Benefit die Größe, die sagt, ob es jemanden stört.

Die Unsicherheit gehört dazu, auch wenn das Feld uneins ist, wie. Vickers und Kollegen argumentieren 2023, dass Signifikanztests für den Net Benefit schädlich wären: Wer entscheiden muss, wählt den höheren Erwartungsnutzen, unabhängig vom p-Wert. Ein Gegenstrang der Literatur drückt die Unsicherheit stattdessen als Wert weiterer Information aus (EVPI, EVSI), ein bayesianischer Weg existiert ebenfalls (bayesdca, bislang nur auf GitHub).

Ich habe oben deshalb keine Konfidenzintervalle gezeichnet, sondern das 5. bis 95. Perzentil über 200 Läufe berichtet, dazu die Häufigkeit, mit der eine Strategie schlechter abschneidet als „alle warten". Zwei Hinweise zur Einordnung: Jeder Lauf zieht einen neuen Datensatz und teilt ihn neu, die Streuung enthält also beides. Und sie ersetzt keine Inferenz. Sie zeigt, wie stabil die Aussage über wiederholte Stichproben desselben Prozesses ist, nicht mehr.

WAS DAS FÜR DIE PIPELINE HEISST

Der Schwellenbereich, die Kalibrierungs-Steigung und der Net Benefit an den vereinbarten Schwellen gehören in dasselbe Monitoring wie die AUC (automatisiertes Reporting und reproduzierbare Pipelines). Ein Modell, dessen Steigung von 0,96 auf 0,50 wandert, sieht in der AUC unverändert aus und kann trotzdem an der Stelle, an der entschieden wird, seinen Nutzen verloren haben.

Fazit

Die AUC beantwortet die Frage „sortiert mein Modell richtig?". Die Frage im Raum lautet meistens „wird die Entscheidung besser?". Das sind zwei Fragen, und die zweite braucht eine Größe, in der das Kostenverhältnis vorkommt. Der Net Benefit ist diese Größe. Er kostet ein paar Zeilen Code und ein Gespräch mit dem Fachbereich, das ohnehin fällig ist.

Das Verfahren ist dabei domänenneutral und passt auf jede Ja-Nein-Entscheidung mit asymmetrischen Kosten. Die Literatur dazu ist trotzdem fast vollständig medizinisch: Eine Suche nach peer-reviewten, methodisch eigenständigen Anwendungen in Instandhaltung, Risikosteuerung oder Ressourcenplanung bleibt leer. Was es außerhalb der Medizin gibt, ist die benachbarte Tradition des cost-sensitive learning mit Kostenmatrizen: dieselbe Grundidee, andere Sprache, andere Fachgemeinschaft, aber ohne Entscheidungskurve und ohne die Referenzstrategien „alle" und „keinen", die den Vergleich erst interpretierbar machen.

Drei Anlässe, bei denen sich das lohnt

AUS DERSELBEN REIHE

Vorhersageintervalle für XGBoost-Prognosen: Conformal Prediction in R. Wie sich Prognoseunsicherheit mit nachprüfbarer Überdeckung ausweisen lässt.

Kennzahlenberichte in R automatisieren: Funnel Plots statt fester Schwellenwerte. Warum ein fester Referenzwert die Fallzahl misst und nicht die Leistung.

ÄHNLICHE FRAGESTELLUNG?

Ein Modell, aus dem eine Handlungsregel werden soll: Im 15-minütigen Erstgespräch kläre ich, welche Prüfgröße dazugehört und wie sie in den Betrieb kommt.

15-MIN-TERMIN BUCHEN →

Wie Prognosemodelle bei sove.it gebaut, geprüft und in Betrieb genommen werden: Predictive Analytics und produktive R-Anwendungen.

Alle Zahlen stammen aus einem tatsächlich gelaufenen Beispiel mit simulierten Daten (4.000 Anlagen, drei Merkmale, Prävalenz 0,136, set.seed(2026), 200 Wiederholungen mit je neuem Datensatz und neuem Split): keine Projektergebnisse und keine illustrativen Werte. Der Lauf erfolgte in einem Container mit R 4.1.2; CRAN war aus der Umgebung nicht erreichbar, dcurves ist deshalb nicht gegen die Handrechnung gelaufen. Die Angaben zum Paket beruhen auf seiner Dokumentation. Modell B ist eine streng monotone Transformation von Modell A und damit bewusst konstruiert; es zeigt, dass die AUC gegen Kalibrierung blind ist, und ist kein Modell, das jemand so bauen würde. Der Net Benefit, die AUC und die Kalibrierungs-Steigung sind der oben gezeigte Code.

Quellen