flowchart LR
E["Erfahrung"] --> K["Weiterbildung"]
E --> G["Gehalt"]
K -- "gesuchter Effekt" --> G
Kausale Inferenz
Die Daten sind so erzeugt, dass der wahre Effekt bekannt ist: 3 für die Weiterbildung, 4 für die Massnahme. Nur so lässt sich zeigen, welches Verfahren ihn trifft. R und Python sehen dieselben Werte aus dem Lehmer-Generator.
Kurzsteckbrief
| Fragestellung | Wie gross ist der Effekt einer Behandlung, wenn niemand die Zuteilung zufällig bestimmt hat? |
| Grundproblem | Wer behandelt wird, unterscheidet sich oft auch sonst von den anderen |
| Werkzeuge | Adjustierung in der Regression, Schichtung, Matching, Difference-in-Differences, Instrumentvariablen |
| Was die Verfahren liefern | eine Effektschätzung, die unter benannten Annahmen kausal gelesen werden darf |
| R | lm() mit Kontrollvariablen, lm(y ~ gruppe * zeit) für Difference-in-Differences; Matching mit MatchIt |
| Python | smf.ols() ebenso; Matching und mehr mit DoWhy |
| Verwandte Seiten | Versuchsplanung und A/B-Tests, multiple lineare Regression, Korrelation |
Wann diese Methode, wann nicht
Wann immer ein Experiment nicht möglich, zu teuer oder unethisch ist, bleiben Beobachtungsdaten: Wer eine Weiterbildung besucht hat, wer in einer Region mit neuer Massnahme lebt, wer ein Medikament nimmt. Die Frage ist dieselbe wie im Experiment, aber die Antwort braucht zusätzliche Annahmen, und die müssen ausgesprochen werden.
| Situation | Stattdessen |
|---|---|
| Zuteilung lässt sich zufällig steuern | A/B-Test oder Experiment, das ist immer vorzuziehen |
| Nur ein Zusammenhang ist gefragt, keine Ursache | Korrelation oder Regression ohne kausale Lesart |
| Vorhersage steht im Vordergrund | Vorhersagemodelle; ob ein Prädiktor kausal wirkt, ist dafür unwichtig |
Grundidee und Modell
Ein Confounder beeinflusst sowohl die Behandlung als auch das Ergebnis:
Wer nur Gehälter mit und ohne Weiterbildung vergleicht, misst beide Wege von Erfahrung zu Gehalt mit. Die Verfahren unterscheiden sich darin, wie sie den Umweg über den Confounder schliessen:
| Verfahren | Wie es den Confounder behandelt | Zentrale Annahme |
|---|---|---|
| Adjustierung | Confounder als Kontrollvariable in der Regression | alle Confounder gemessen, Form des Zusammenhangs richtig |
| Schichtung und Matching | nur Personen mit ähnlichem Confounder vergleichen | alle Confounder gemessen, Schichten fein genug |
| Difference-in-Differences | zeitlich konstante Unterschiede zwischen Gruppen fallen durch Differenzbildung weg | ohne Massnahme wären beide Gruppen parallel verlaufen |
| Instrumentvariable | eine Grösse nutzen, die nur über die Behandlung wirkt | das Instrument hat keinen anderen Weg zum Ergebnis |
Voraussetzungen und ihre Prüfung
| Voraussetzung | Was sie bedeutet | Prüfung | Folge bei Verletzung | Vorgehen |
|---|---|---|---|---|
| Keine ungemessenen Confounder | alles, was Behandlung und Ergebnis zugleich beeinflusst, ist in den Daten | nicht mit Daten prüfbar; Fachwissen, Diagramm wie oben | verzerrte Schätzung in unbekannter Richtung | Sensitivitätsanalyse, andere Verfahren |
| Überlappung | für jeden Confounderwert gibt es Behandelte und Unbehandelte | Verteilung des Confounders je Gruppe vergleichen | Schätzung beruht auf Extrapolation | auf den Bereich mit Überlappung beschränken |
| Keine Kontrolle von Mediatoren | nichts adjustieren, was selbst eine Folge der Behandlung ist | Diagramm | Effekt wird kleingerechnet | nur Grössen vor der Behandlung aufnehmen |
| Parallele Trends (für DiD) | ohne Massnahme gleiche Entwicklung | Verlauf über mehrere Perioden vor der Massnahme | DiD-Schätzung verzerrt | mehr Vorperioden, anderes Vergleichsgebiet |
Output lesen
Die Verfahren auf dieser Seite verwenden die gewöhnliche Regression. Neu ist nicht der Output, sondern welche Zeile kausal gelesen wird:
| Modell | Zeile mit dem Effekt | Was sie bedeutet |
|---|---|---|
gehalt ~ kurs + erfahrung |
kurs |
Gehaltsunterschied mit Weiterbildung bei gleicher Erfahrung |
umsatz ~ massnahme * nachher |
massnahme:nachher |
zusätzliche Veränderung in der Region mit Massnahme, über die allgemeine Veränderung hinaus |
Alle anderen Koeffizienten sind Hilfsgrössen. Der Koeffizient von erfahrung etwa ist nicht der kausale Effekt der Erfahrung, weil für ihn andere Confounder gelten würden.
Interpretationsfallen
- Korrelation ist nicht Kausalität, auch mit vielen Kontrollvariablen nicht. Adjustierung hilft nur gegen gemessene Confounder.
- Mehr Kontrollvariablen sind nicht automatisch besser. Ein Mediator oder eine gemeinsame Folge von Behandlung und Ergebnis erzeugen Verzerrung, statt sie zu beseitigen.
- Grobe Schichten lassen Verzerrung übrig. Innerhalb einer Schicht von 14 bis 20 Jahren Erfahrung unterscheiden sich die Gruppen immer noch. Beispiel 2 misst den Rest.
- Die Tabelle-2-Falle: In einem Modell ist nur der Koeffizient der Behandlung kausal gemeint; die übrigen im selben Atemzug kausal zu interpretieren ist ein verbreiteter Fehler.
- Vorher-nachher allein ist kein Effekt. Alles, was sich in derselben Zeit sonst verändert hat, steckt mit darin. Beispiel 3 zeigt es.
Ergebnis berichten
Unter der Annahme, dass [Confounder] die relevanten gemeinsamen Ursachen erfassen, ist [Behandlung] mit [Wert] [Einheit] höherem [Ergebnis] verbunden (95-Prozent-Konfidenzintervall [unten] bis [oben], [Verfahren]). Ungemessene Confounder wie Beispiele können nicht ausgeschlossen werden.
Immer genannt werden: das Verfahren, die Identifikationsannahme im Klartext, die adjustierten Grössen und die bekannten Grenzen.
Abgrenzung zu verwandten Methoden
| Methode | Wann diese statt der hier beschriebenen |
|---|---|
| Versuchsplanung und A/B-Tests | Zuteilung lässt sich randomisieren |
| Multiple lineare Regression | Zusammenhänge beschreiben oder vorhersagen, ohne kausalen Anspruch |
| Gemischte Modelle | Paneldaten mit wiederholten Messungen; lassen sich mit DiD kombinieren |
Beispiele
Jedes Beispiel steht in einem eigenen Reiter.
Frage und Datenlage
Verdienen Beschäftigte mit Weiterbildung mehr? 400 Personen, erfasst sind Erfahrung in Jahren, Weiterbildung ja oder nein und Gehalt in Tausend Franken. Erfahrene haben häufiger eine Weiterbildung besucht.
Voraussetzungen prüfen
round(c(anteil_kurs = mean(firma$kurs)), 4)anteil_kurs
0.4675
round(tapply(firma$erfahrung, firma$kurs, mean), 2) 0 1
8.78 13.84
print("Anteil Kurs:", round(firma["kurs"].mean(), 4))Anteil Kurs: 0.4675
print(firma.groupby("kurs")["erfahrung"].mean().round(2))kurs
0 8.78
1 13.84
Name: erfahrung, dtype: float64
Mit Weiterbildung liegt die Erfahrung im Mittel bei 13.84 Jahren, ohne bei 8.78. Die beiden Gruppen unterscheiden sich also schon vor jeder Wirkung des Kurses.
Rechnung
naiv <- diff(tapply(firma$gehalt, firma$kurs, mean))
adjustiert <- lm(gehalt ~ kurs + erfahrung, data = firma)
round(c(naiv = unname(naiv), adjustiert = unname(coef(adjustiert)["kurs"]),
se = summary(adjustiert)$coefficients["kurs", "Std. Error"]), 3) naiv adjustiert se
14.856 4.549 0.703
round(confint(adjustiert)["kurs", ], 3) 2.5 % 97.5 %
3.166 5.932
mittel = firma.groupby("kurs")["gehalt"].mean()
adjustiert = smf.ols("gehalt ~ kurs + erfahrung", firma).fit()
print("naiv:", round(mittel[1] - mittel[0], 3),
" adjustiert:", round(adjustiert.params["kurs"], 3),
" se:", round(adjustiert.bse["kurs"], 3))naiv: 14.856 adjustiert: 4.549 se: 0.703
print("Intervall:", np.round(adjustiert.conf_int().loc["kurs"].values, 3))Intervall: [3.166 5.932]
Output Zeile für Zeile
| Ausgabe | Wert hier | Bedeutung | Wie er zu lesen ist |
|---|---|---|---|
| naiver Unterschied | 14.856 | Gehalt mit minus ohne Weiterbildung | fast fünfmal der wahre Effekt von 3; enthält den Umweg über die Erfahrung |
| adjustierter Effekt | 4.549 | Unterschied bei gleicher Erfahrung | viel näher am wahren Wert |
| Standardfehler | 0.703 | Unsicherheit der adjustierten Schätzung | |
| Intervall | 3.166 bis 5.932 | 95-Prozent-Konfidenzintervall | Es verfehlt den wahren Wert 3 knapp. Bei 95-Prozent-Intervallen passiert das in jedem zwanzigsten Datensatz, hier ist es einer davon. |
Interpretation und Ergebnissatz
Die Adjustierung beseitigt den grössten Teil der Verzerrung. Dass sie hier funktioniert, liegt an zwei Eigenschaften der erzeugten Daten, die in echten Daten niemand garantiert: Erfahrung ist der einzige Confounder, und sie wirkt linear auf das Gehalt.
Bei gleicher Erfahrung verdienen Beschäftigte mit Weiterbildung im Mittel 4.5 Tausend Franken mehr (95-Prozent-Konfidenzintervall 3.2 bis 5.9, lineare Regression mit Erfahrung als Kontrollvariable), unter der Annahme, dass Erfahrung die relevante gemeinsame Ursache ist.
Frage und Datenlage
Statt die Erfahrung als Zahl ins Modell zu nehmen, werden die Personen in vier Erfahrungsklassen eingeteilt: 2 bis 6, 6 bis 10, 10 bis 14 und 14 bis 20 Jahre. Innerhalb jeder Klasse wird der Gehaltsunterschied berechnet, danach nach der Klassengrösse gemittelt.
Rechnung
firma$schicht <- cut(firma$erfahrung, breaks = c(0, 6, 10, 14, 20))
je_schicht <- sapply(split(firma, firma$schicht), function(s) {
c(ohne = mean(s$gehalt[s$kurs == 0]), mit = mean(s$gehalt[s$kurs == 1]),
n_ohne = sum(s$kurs == 0), n_mit = sum(s$kurs == 1))
})
je_schicht <- rbind(je_schicht, diff = je_schicht["mit", ] - je_schicht["ohne", ])
round(je_schicht, 2) (0,6] (6,10] (10,14] (14,20]
ohne 66.69 75.26 85.10 92.32
mit 70.88 82.59 88.59 98.54
n_ohne 66.00 68.00 49.00 30.00
n_mit 11.00 28.00 45.00 103.00
diff 4.19 7.32 3.49 6.22
gewicht <- je_schicht["n_ohne", ] + je_schicht["n_mit", ]
round(weighted.mean(je_schicht["diff", ], gewicht), 3)[1] 5.452
firma["schicht"] = pd.cut(firma["erfahrung"], [0, 6, 10, 14, 20])
tabelle = firma.groupby(["schicht", "kurs"], observed=True)["gehalt"].agg(["mean", "size"]).unstack()
tabelle["diff"] = tabelle[("mean", 1)] - tabelle[("mean", 0)]
tabelle["n"] = tabelle[("size", 0)] + tabelle[("size", 1)]
print(tabelle.round(2)) mean size diff n
kurs 0 1 0 1
schicht
(0, 6] 66.69 70.88 66 11 4.19 77
(6, 10] 75.26 82.59 68 28 7.32 96
(10, 14] 85.10 88.59 49 45 3.49 94
(14, 20] 92.32 98.54 30 103 6.22 133
print("gewichtet:", round(np.average(tabelle["diff"], weights=tabelle["n"]), 3))gewichtet: 5.452
Output Zeile für Zeile
| Schicht | ohne Kurs | mit Kurs | Differenz | Wie es zu lesen ist |
|---|---|---|---|---|
| 2 bis 6 Jahre | 66 Personen | 11 Personen | 4.19 | wenige Behandelte, unsichere Differenz |
| 6 bis 10 Jahre | 68 | 28 | 7.32 | |
| 10 bis 14 Jahre | 49 | 45 | 3.49 | |
| 14 bis 20 Jahre | 30 | 103 | 6.22 | umgekehrtes Verhältnis: hier sind die Unbehandelten die Minderheit |
| gewichtet | 5.452 | weiter vom wahren Wert 3 entfernt als die Adjustierung |
Interpretation und Ergebnissatz
Innerhalb der Schicht von 14 bis 20 Jahren sind die Weitergebildeten immer noch erfahrener als die anderen, weil Erfahrene in jeder Schicht häufiger einen Kurs besuchen. Dieser Rest an Confounding bleibt in der Differenz stecken. Feinere Schichten oder Matching auf die genaue Erfahrung verringern ihn, kosten aber Beobachtungen je Vergleich.
Die Schichtung nach vier Erfahrungsklassen ergibt einen Effekt von 5.45 Tausend Franken; die groben Klassen lassen einen Teil der Verzerrung durch Erfahrung bestehen.
Frage und Datenlage
Region B führte eine Verkaufsmassnahme ein, Region A nicht. Gemessen wurde der Umsatz je Filialwoche vor und nach der Einführung, je 50 Werte. Region B lag schon vorher höher, und in beiden Regionen stieg der Umsatz in der zweiten Periode saisonal. Welcher Anteil des Anstiegs in B geht auf die Massnahme zurück?
Rechnung
m <- tapply(did$umsatz, list(did$region, did$nachher), mean)
round(m, 3) 0 1
A 99.268 106.352
B 106.674 116.796
round(c(nachher_b_minus_a = m["B", "1"] - m["A", "1"],
b_nachher_minus_vorher = m["B", "1"] - m["B", "0"],
did_von_hand = (m["B", "1"] - m["B", "0"]) - (m["A", "1"] - m["A", "0"])), 3) nachher_b_minus_a b_nachher_minus_vorher did_von_hand
10.444 10.122 3.038
modell <- lm(umsatz ~ massnahme * nachher, data = did)
round(summary(modell)$coefficients, 4) Estimate Std. Error t value Pr(>|t|)
(Intercept) 99.268 0.8677 114.3999 0.0000
massnahme 7.406 1.2272 6.0351 0.0000
nachher 7.084 1.2272 5.7727 0.0000
massnahme:nachher 3.038 1.7355 1.7505 0.0816
round(confint(modell)["massnahme:nachher", ], 3) 2.5 % 97.5 %
-0.385 6.461
m = did.groupby(["region", "nachher"])["umsatz"].mean().unstack()
print(m.round(3))nachher 0 1
region
A 99.268 106.352
B 106.674 116.796
print("nachher B minus A:", round(m.loc["B", 1] - m.loc["A", 1], 3),
" B nachher minus vorher:", round(m.loc["B", 1] - m.loc["B", 0], 3),
" DiD von Hand:", round((m.loc["B", 1] - m.loc["B", 0]) - (m.loc["A", 1] - m.loc["A", 0]), 3))nachher B minus A: 10.444 B nachher minus vorher: 10.122 DiD von Hand: 3.038
modell = smf.ols("umsatz ~ massnahme * nachher", did).fit()
print(pd.DataFrame({"schaetzung": modell.params, "se": modell.bse,
"p": modell.pvalues}).round(4)) schaetzung se p
Intercept 99.268 0.8677 0.0000
massnahme 7.406 1.2272 0.0000
nachher 7.084 1.2272 0.0000
massnahme:nachher 3.038 1.7355 0.0816
print("Intervall:", np.round(modell.conf_int().loc["massnahme:nachher"].values, 3))Intervall: [-0.385 6.461]
Output Zeile für Zeile
| Ausgabe | Wert hier | Bedeutung | Wie er zu lesen ist |
|---|---|---|---|
| Mittel A vorher, nachher | 99.268, 106.352 | Region ohne Massnahme | Anstieg um 7.084, das ist die allgemeine Entwicklung |
| Mittel B vorher, nachher | 106.674, 116.796 | Region mit Massnahme | Anstieg um 10.122 |
massnahme |
7.406 | Niveauunterschied vor der Massnahme | B lag schon vorher höher; das ist kein Effekt |
nachher |
7.084 | allgemeiner Anstieg | gilt für beide Regionen |
massnahme:nachher |
3.038 | Difference-in-Differences | zusätzlicher Anstieg in B, die Schätzung des Effekts |
| Standardfehler, p | 1.7355, 0.0816 | Unsicherheit | bei je 50 Werten nicht signifikant |
| Intervall | -0.385 bis 6.461 | 95-Prozent-Konfidenzintervall | enthält den wahren Wert 4 und auch die Null |
Interpretation und Ergebnissatz
Die beiden naiven Vergleiche liegen weit daneben: Nachher B gegen A ergibt 10.444, weil der alte Niveauunterschied mitgezählt wird; vorher gegen nachher in B ergibt 10.122, weil der saisonale Anstieg mitgezählt wird. Die doppelte Differenz entfernt beides und landet bei 3.038. Mit 50 Werten je Zelle ist die Schätzung aber unsicher. Die Annahme paralleler Trends lässt sich mit nur einer Vorperiode nicht prüfen.
Unter der Annahme paralleler Trends erhöhte die Massnahme den Umsatz um 3.0 Einheiten (95-Prozent-Konfidenzintervall -0.4 bis 6.5, p = 0.08, Difference-in-Differences mit je 50 Filialwochen). Der Effekt ist mit diesen Daten nicht von null zu unterscheiden.
Verständnisfragen
Eine Studie findet, dass Personen mit Fitnessabo seltener krank sind, und adjustiert für Alter und Geschlecht. Welcher Einwand wiegt am schwersten?
Ein Modell schätzt den Effekt einer Schulung auf den Umsatz. Soll die Zahl der Kundenkontakte nach der Schulung als Kontrollvariable aufgenommen werden?
Was ist die zentrale Annahme hinter Difference-in-Differences?