Kausale Inferenz

Versuchsplanung
Regression
Interpretation
R
Python
Ursache statt Zusammenhang aus Beobachtungsdaten: Confounder, Adjustierung, Schichtung und Difference-in-Differences.

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:

flowchart LR
    E["Erfahrung"] --> K["Weiterbildung"]
    E --> G["Gehalt"]
    K -- "gesuchter Effekt" --> G
Abbildung 1: Erfahrung als Confounder: Sie wirkt auf die Weiterbildung und auf das Gehalt.

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?

Gesundheitsbewusstsein beeinflusst Abo und Krankheit und ist nicht gemessen
Richtig. Das ist ein ungemessener Confounder. Gegen ihn hilft keine Adjustierung der vorhandenen Variablen.
Die Stichprobe ist zu klein
Mehr Daten verkleinern die Unsicherheit, nicht die Verzerrung durch einen fehlenden Confounder.
Alter hätte nicht adjustiert werden dürfen
Alter wirkt auf Abo und Krankheit und liegt zeitlich davor; es zu adjustieren ist richtig.

Ein Modell schätzt den Effekt einer Schulung auf den Umsatz. Soll die Zahl der Kundenkontakte nach der Schulung als Kontrollvariable aufgenommen werden?

Nein, sie ist vermutlich ein Mediator, über den die Schulung wirkt
Richtig. Wer den Mediator konstant hält, rechnet den Teil des Effekts heraus, der über mehr Kundenkontakte läuft.
Ja, jede Variable mit Einfluss auf den Umsatz gehört ins Modell
Das gilt für Confounder, nicht für Folgen der Behandlung.
Ja, sonst ist das Modell nicht signifikant
Signifikanz ist kein Kriterium für die Auswahl der Kontrollvariablen.

Was ist die zentrale Annahme hinter Difference-in-Differences?

Ohne die Massnahme hätten sich beide Gruppen parallel entwickelt
Richtig. Unterschiede im Niveau sind erlaubt, Unterschiede in der Entwicklung nicht.
Beide Gruppen lagen vorher auf demselben Niveau
Gerade das muss nicht sein; der Niveauunterschied fällt durch die Differenzbildung weg.
Die Massnahme wurde zufällig zugeteilt
Dann wäre ein einfacher Vergleich möglich; DiD ist gerade für den Fall ohne Randomisierung da.

Verlinkte Ressourcen