Kennzahlenberichte in R automatisieren: Funnel Plots statt fester Schwellenwerte
- Gegeben: Ein monatlicher Kennzahlenbericht vergleicht 50 Einheiten sehr unterschiedlicher Größe (25 bis 1.213 Fälle) gegen einen Referenzwert. Auffällige Einheiten gehen in ein Gespräch.
- Problem: Die Bewertungszeile
auffaellig = ergebnis < referenzbehandelt eine Einheit mit 30 Fällen wie eine mit 900, obwohl die erste naturgemäß stärker streut. - Verfahren: Funnel Plot mit fallzahlabhängigen Kontrollgrenzen nach Spiegelhalter, z = 3,09, additive Overdispersion-Korrektur φ mit Winsorisierung bei 10/90 Prozent.
- Ergebnis im Beispiel: 2,050 Fehlalarme je Bericht gegen 0,159, also Faktor 12,9. Beim festen Wert treffen 87,6 Prozent der Fehlalarme die kleinere Hälfte der Einheiten.
- Preis: Die gefundenen echten Ausreißer gehen von 1,926 auf 1,552 zurück, ein Verlust von 19 Prozent Trefferquote.
Automatisierung skaliert den Bericht und den methodischen Fehler darin gleich mit. Ein fester Referenzwert erzeugt im simulierten Beispiel 2,05 Fehlalarme je Bericht, fallzahlabhängige Grenzen 0,16. Fast neun von zehn dieser Fehlalarme treffen Einheiten aus der kleineren Hälfte.
Das Praxisproblem
Ein monatlich automatisch laufender Kennzahlenbericht spart Handarbeit, Copy-Paste-Fehler und Formatdiskussionen. Genau deshalb liest ihn irgendwann niemand mehr gegen.
Und irgendwo in diesem Bericht steht eine Zeile wie diese:
auffaellig <- ergebnis < referenz
Sie ist schnell geschrieben und sofort erklärbar. Sie hat nur einen Nachteil: Sie behandelt eine Einheit mit 30 Fällen genauso wie eine mit 900.
Das ist keine Feinheit. Wenn die wahre Qualität einer Einheit bei 0,86 liegt und der Referenzwert bei 0,80, dann rutscht eine Einheit mit 30 Fällen allein durch Zufall mit Wahrscheinlichkeit 0,117 unter die Marke. Bei 900 Fällen passiert das praktisch nie:
library(dplyr) tibble(n = c(30, 60, 120, 300, 900)) |> mutate(p_fehlalarm = pbinom(ceiling(0.80 * n) - 1, n, 0.86))
| Fallzahl n | 30 | 60 | 120 | 300 | 900 |
|---|---|---|---|---|---|
| P(fälschlich auffällig) | 0,117 | 0,069 | 0,026 | 0,002 | 0,000 |
binomial, wahre Qualität 0,86, Referenzwert 0,80
Der Bericht sagt also nicht „diese Einheit ist schlecht". Er sagt „diese Einheit ist klein". Und weil er jeden Monat läuft, sagt er das jeden Monat neu.
Goldstein und Spiegelhalter haben die statistischen Grenzen von Einrichtungsvergleichen 1996 beschrieben. Anhøj und Hellesøe haben 2017 in BMJ Quality & Safety nachgelegt: Ampellogik über feste Zielwerte lenkt von Zufallsvariation ab, statt sie sichtbar zu machen. Und Schmidtke und Kollegen haben im selben Jahr nachgesehen, wie oft das in der Praxis berücksichtigt wird: In 30 englischen NHS-Board-Berichten fanden sie 1.488 Diagramme, von denen 88, also sechs Prozent, überhaupt darstellten, welche Rolle der Zufall spielt.
Die deutsche Qualitätssicherung im Gesundheitswesen stellt seit 2022 schrittweise um, weg vom festen Schwellenwert und hin zu einer fallzahlabhängigen Einstufung, Verfahren für Verfahren. Die Begründung dort lautet, dass die Variabilität einer Kennzahl fallzahlabhängig ist und ihr Ignorieren dazu führt, dass allein aus stochastischen Gründen bei Leistungserbringern mit geringer Fallzahl viele Auffälligkeiten auftreten. Die Einstufung selbst läuft in diesem Rahmen bayesianisch; der Funnel Plot dient der Darstellung. In automatisierten Berichten außerhalb der Qualitätssicherung steht die Zeile von oben weiter drin.
Die Idee in einem Satz
Die Vergleichsgrenze muss mit der Fallzahl mitwachsen: eng bei großen Einheiten, weit bei kleinen, und um genau den Betrag weiter, den die Streuung tatsächlich hergibt.
Trägt man die Grenzen über der Fallzahl auf, ergibt sich ein Trichter. Daher der Name.
Ein Satz Abgrenzung, weil der Begriff auf Deutsch belegt ist: Wer „Funnel Plot" sucht, landet fast immer beim Trichterdiagramm der Meta-Analyse: Effektschätzer gegen Präzision, Asymmetrie als Hinweis auf Publikationsbias, Egger-Test. Das ist ein anderes Verfahren mit demselben Bild. Hier geht es nicht um Asymmetrie über Studien hinweg, sondern darum, ob eine einzelne Einheit ihre fallzahlabhängige Kontrollgrenze verlässt. Auch in R sind das zwei getrennte Paketfamilien: metaviz und metafor für die Meta-Analyse, FunnelPlotR und controlcharts für den Einrichtungsvergleich.
Der Code
50 Einheiten, sehr unterschiedliche Fallzahlen (Median 190, Spanne 25 bis 1213). Die wahre Qualität liegt bei 0,86 und streut wenig, außer bei zwei Einheiten, die tatsächlich schlechter sind (0,72). Im simulierten Datensatz ist bekannt, welche beiden das sind. Im Betrieb ist es das nicht, und genau darum geht es.
library(dplyr) set.seed(2026) N <- 50; ZIELWERT <- 0.86; TAU <- 0.015 REFERENZ <- 0.80 # der Wert, gegen den naiv geprueft wird AUSREISSER <- c(8, 24) # diese beiden sind wirklich schlechter Z <- 3.09 # ~99,8 %, Konvention nach Spiegelhalter (2005) n_faelle <- pmin(pmax(round(exp(rnorm(N, log(180), 1.0))), 25), 2000) p_wahr <- pmin(pmax(rnorm(N, ZIELWERT, TAU), 0.01), 0.99) p_wahr[AUSREISSER] <- 0.72 dat <- tibble( einheit = sprintf("E%02d", seq_len(N)), n_faelle = n_faelle, erfuellt = rbinom(N, n_faelle, p_wahr) ) |> mutate(ergebnis = erfuellt / n_faelle)
Weg A: der Schwellenwert. Eine Zeile, kein Modell, keine Unsicherheit:
dat <- dat |> mutate(auffaellig_schwelle = ergebnis < REFERENZ)
Weg B: Funnel-Grenzen mit Overdispersion-Korrektur. Erst der gepoolte Zielwert, dann der Standardfehler je Einheit, dann φ:
theta_hat <- dat |> summarise(theta = sum(erfuellt) / sum(n_faelle)) |> pull(theta) dat <- dat |> mutate(se = sqrt(theta_hat * (1 - theta_hat) / n_faelle), z = (ergebnis - theta_hat) / se) # phi faengt die Streuung auf, die ueber die reine Binomialstreuung hinausgeht: # unbeobachtete Risikofaktoren, Fallmix, alles, was das Modell nicht kennt. # Winsorisierung bei 10/90 %, damit die echten Ausreisser phi nicht aufblasen; # sonst versteckt das Verfahren genau das, was es finden soll. phi <- dat |> mutate(z_w = pmin(pmax(z, quantile(z, .10)), quantile(z, .90))) |> summarise(phi = max(mean(z_w^2), 1)) |> pull(phi) dat <- dat |> mutate(untere_grenze = theta_hat - Z * se * sqrt(phi), auffaellig_funnel = ergebnis < untere_grenze)
Das war es. theta_hat = 0,8509, phi = 1,01 in diesem Lauf.
Drei Entscheidungen fallen dabei an und gehören dokumentiert: welche Konstruktion der Kontrollgrenzen, welches z, ob und wie winsorisiert wird. Beiwerk ist das nicht. Verburg und Kollegen haben 2018 eine Leitlinie dazu geschrieben, weil in Anwendungsstudien regelmäßig unklar bleibt, welche Variante verwendet wurde; verschiedene Wahlen führen zu verschiedenen Ergebnissen. Wer es produktiv einsetzt, schreibt die Wahl in den Bericht.
Das Ergebnis
Einzellauf. Der Schwellenwert markiert 2 Einheiten, die Funnel-Grenzen 1. Beide markierten Einheiten des Schwellenwerts sind echte Ausreißer, die des Funnels ebenfalls. Hier tut noch niemandem etwas weh. Ein Einzellauf trägt aber keine Aussage. Also 1000 Wiederholungen:
| fester Schwellenwert | Funnel-Grenzen | |
|---|---|---|
| Fehlalarme je Bericht | 2,050 | 0,159 (Faktor 12,9) |
| davon in der kleineren Hälfte der Einheiten | 87,6 % | 27,0 % |
| gefundene echte Ausreißer (von 2) | 1,926 | 1,552 |
φ über die 1000 Läufe: Median 1,135, Spanne 1,000 bis 2,366.
Zwei Zahlen zum Mitnehmen. Erstens: Der Schwellenwert erzeugt fast dreizehnmal so viele Fehlalarme. Zweitens, und das ist die eigentliche Pointe: fast neun von zehn dieser Fehlalarme treffen Einheiten aus der kleineren Hälfte, also aus der Hälfte mit einer Fallzahl unter dem Median. Bei größenneutralen Fehlalarmen wären 50 Prozent zu erwarten. Beim Funnel sind es 27 Prozent, also sogar weniger: Die Grenzen werden bei kleiner Fallzahl so weit, dass dort kaum noch etwas markiert wird.
Und genau das ist der Preis. Der Schwellenwert findet mehr echte Ausreißer: 1,926 gegen 1,552 von zwei, ein Rückgang um 19 Prozent. Wer die Fehlalarme loswerden will, verliert Trennschärfe, und zwar dort, wo sie ohnehin am schwächsten ist. Seaton und Kollegen haben 2013 genau das untersucht: Die Wahrscheinlichkeit, dass ein tatsächlich schlechter Leistungserbringer im Funnel Plot auffällt, ist niedrig, besonders bei kleinen Fallzahlen. Der Trichter schützt die kleinen Einheiten vor falschen Anschuldigungen. Er versteckt sie damit auch.
Wer den Rückgang der Trefferquote weglässt, berichtet das halbe Ergebnis.
Ein Wort zu φ. In diesem Beispiel liegt es bei 1,01, im Median über 1000 Läufe bei 1,135. Die Overdispersion-Korrektur greift hier also kaum. Der ganze Gewinn kommt aus der Fallzahlabhängigkeit der Grenzen. φ ist die Versicherung für den anderen Fall: Daten, in denen mehr streut, als das Binomialmodell erlaubt, weil Fallmix und unbeobachtete Risikofaktoren mitspielen. In echten Qualitätsdaten ist das die Regel. Im simulierten Beispiel ist es das nicht, und das gehört dazugesagt.
So nutze ich das produktiv
Drei Dinge ändern sich, wenn das nicht in einem Skript steht, sondern in einer Pipeline, die monatlich läuft.
Erstens: das Ergebnis-Objekt vom Rendering trennen. Nicht der Bericht rechnet, sondern eine Funktion, die ein geprüftes Ergebnis-Objekt zurückgibt; der Bericht rendert es nur noch. Das ist der Unterschied zwischen „wir haben die Zahl im Bericht gefunden" und „wir können die Zahl testen". In der klinischen Statistik heißt das Muster Analysis Results Data; die Pakete cards und gtsummary bauen darauf auf. Praktisch heißt es: berechne_auffaelligkeiten() gibt einen Data Frame zurück, testthat prüft ihn, und erst danach kommt Word ins Spiel.
Zweitens: die Grenze zeichnen. Für den Bericht statisch: FunnelPlotR (Mainey, NHS-R Community) implementiert Spiegelhalters Methode und nimmt einem laut Paketbeschreibung die additive Overdispersion-Korrektur samt Winsorisierung ab. Für die interaktive Anlage controlcharts (Johnson mit dem Healthcare Quality Intelligence Unit, Western Australia Health, seit August 2026 auf CRAN): rechnet und zeichnet laut Beschreibung vollständig in JavaScript und läuft damit ohne Shiny-Server in jedem HTML-Bericht. Daraus wird eine Entscheidungsregel: statisch, was gedruckt wird, interaktiv, was geklickt wird.
Drittens: der Weg nach Word. Verlangt der Auftraggeber ein .docx, gibt es drei Wege, und die Wahl ist eine Entscheidung und kein Geschmack:
| Weg | Wann | Grenze |
|---|---|---|
officer programmatisch | volle Kontrolle über das Layout, Berichte mit variabler Struktur | jeder Absatz ist Code |
R Markdown + officedown | wiederkehrende Berichte mit fester Struktur, Corporate Design über Referenz-.docx | unterstützt kein Quarto |
Quarto + Referenz-.docx | wenn der Rest des Hauses ohnehin Quarto ist | Cross-Referenzen bleiben Klartext, Deckblatt ungelöst |
Die Faustregel, die sich bei mir durchgesetzt hat: feste Struktur und Corporate Design → officedown; variable Struktur oder Anlagen, die sich je Lauf unterscheiden → officer; Quarto nur, wenn Word nicht das primäre Ziel ist.
Automatisierung skaliert den Bericht und den methodischen Fehler darin gleich mit. Eine Pipeline, die monatlich 40 Berichte erzeugt, kommt bei 2,05 Fehlalarmen je Bericht auf gut 80 im Monat und knapp tausend im Jahr. Das sind Gespräche, die nicht hätten stattfinden müssen, überwiegend mit den kleinen Einheiten.
Fazit
Ein fester Schwellenwert verwechselt Ergebnis und Fallzahl. Fallzahlabhängige Grenzen kosten rund zwanzig Zeilen R und senken die Fehlalarme im Beispiel um den Faktor 12,9, für den Preis von 19 Prozent Trefferquote, die man beim Namen nennen muss.
Die Frage vor dem nächsten automatisierten Bericht lautet deshalb nicht „welches Werkzeug?", sondern: Wonach entscheidet die Bewertungszeile, nach der Leistung oder nach der Größe?
Drei Anlässe, bei denen sich das lohnt
- Ein Bericht vergleicht Standorte, Regionen, Filialen oder Einrichtungen mit sehr unterschiedlicher Größe.
- Dieselben kleinen Einheiten fallen jeden Monat auf, ohne dass sich etwas ändert.
- Die Bewertungsregel im Bericht ist älter als die Datengrundlage, auf die sie angewandt wird.
Decision Curve Analysis in R: wann ein Modell eine Entscheidung wirklich verbessert. Warum zwei Modelle mit identischer AUC unterschiedlich nützlich sein können.
Vorhersageintervalle für XGBoost-Prognosen: Conformal Prediction in R. Prognoseintervalle mit nachprüfbarer Überdeckung.
Ein automatisierter Bericht, der Einheiten sehr unterschiedlicher Größe vergleicht: 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 Kennzahlenberichte bei sove.it gebaut und in Betrieb genommen werden: automatisiertes Reporting und produktive R-Anwendungen.
Alle Zahlen stammen aus einem tatsächlich gelaufenen Beispiel mit simulierten Daten (50 Einheiten, Median 190 Fälle, Spanne 25 bis 1213, set.seed(2026), 1000 Wiederholungen): keine Projektergebnisse und keine illustrativen Werte. Der Lauf erfolgte am 01.09.2026 in einem Container mit R 4.1.2 und den Ubuntu-Paketständen von 2022 (dplyr 1.0.8, ggplot2 3.3.5); CRAN war aus der Umgebung nicht erreichbar. Das betrifft die Werkzeugversionen und nicht die Rechnung: Zielwert, Standardfehler, φ und die Grenzen sind einfache Arithmetik und hängen an keiner Paketversion. Die Angaben zu FunnelPlotR und controlcharts beruhen auf den Paketbeschreibungen und nicht auf einem eigenen Lauf.
Quellen
- Spiegelhalter, D. J. (2005): Funnel plots for comparing institutional performance. Statistics in Medicine 24(8), 1185–1202.
- Spiegelhalter, D. J. (2005): Handling over-dispersion of performance indicators. Quality and Safety in Health Care 14(5), 347–351.
- Goldstein, H. & Spiegelhalter, D. J. (1996): League Tables and Their Limitations. Journal of the Royal Statistical Society A 159(3), 385 ff.
- Verburg, I. W. M., Holman, R., Peek, N., Abu-Hanna, A. & de Keizer, N. F. (2018): Guidelines on constructing funnel plots for quality indicators. Statistical Methods in Medical Research 27(11), 3350–3366.
- Seaton, S. E., Barker, L., Lingsma, H. F., Steyerberg, E. W. & Manktelow, B. N. (2013): What is the probability of detecting poorly performing hospitals using funnel plots? BMJ Quality & Safety 22(10), 870–876.
- Seaton, S. E. & Manktelow, B. N. (2012): The probability of being identified as an outlier with commonly used funnel plot control limits for the standardised mortality ratio. BMC Medical Research Methodology 12, 98.
- Anhøj, J. & Hellesøe, A.-M. B. (2017): The problem with red, amber, green. BMJ Quality & Safety 26(1), 81–84.
- Schmidtke, K. A. et al. (2017): Considering chance in quality and safety performance measures. BMJ Quality & Safety 26(1), 61–69.
- Hengelbrock, J., Rauh, J., Cederbaum, J., Kähler, M. & Höhle, M. (2023): Hospital Profiling Using Bayesian Decision Theory. Biometrics 79(3), 2757–2769.
- Egger, M., Davey Smith, G., Schneider, M. & Minder, C. (1997): Bias in meta-analysis detected by a simple, graphical test. BMJ 315(7109), 629–634. (Abgrenzung Meta-Analyse)
- Sterne, J. A. C. et al. (2011): Recommendations for examining and interpreting funnel plot asymmetry in meta-analyses of randomised controlled trials. BMJ 343, d4002.
- R-Pakete:
FunnelPlotR0.6.0 (Mainey) ·controlcharts0.0.19 (Johnson) ·qicharts20.8.1 (Anhøj) ·officer,officedown,flextable(Gohel)