2/1/2020

Causal Diagrams

What are they?

  • Simple representations of structural models
  • Without “cycles” (directed acyclic graph)
  • These allow us to apply some graph theory tricks to statistics
  • Grew out of the work of Judea Pearl

Why?

Why teach with causal diagrams?

  • Helps students think about model-building in a simple way: how can I represent these economic concepts in a model?
  • Once it’s drawn, identification of any given relationship is automatic
  • Helps with selection of control variables - no kitchen sink!
  • Makes the concept of “identification” much clearer
  • Doesn’t rely on abstract difficult concepts like ignorability or relationships with error terms
  • Doesn’t restrict identification to a linear regression context

Why not?

What are the difficulties?

  • Formally, these are entirely nonparametric. So to enforce shape restrictions like interactions or monotonicity, you have to “cheat” a little - I think that’s ok for UGs
  • Identification relies on correctness of the model (obv). Yes, there’s an echo of the structural-vs-reduced-form debate here. You need to do a little more work on the model uncertainty to justify not just doing regression + controls
  • A little tricker to represent stuff like ATE, LATE, ATT, etc. - this also requires “outside-the-graph” explanation
  • Change of mindset: we are trained in PO. This isn’t really that different (mathematically equivalent systems), but different

Other notes before we start

  • The math underlying the diagrams, the “do-calculus” is interesting and a useful alternative to PO approaches, but IMO not necessary to teach undergrads for our purposes (it’s not like we teach them much PO calculation either). See Pearl & Mackenzie (2018) “The Book of Why” or Pearl (2009) “Causality” for more.
  • For resources, difficult to recommend Pearl too much directly, as his writing is generally not targeted at economists/meeting us where we are. But:

    • Morgan & Winship (2014) “Counterfactuals and Causal Inference”
    • Cunningham (ongoing) “Causal Inference: The Mixtape” (free)
    • Hünermund & Bareinbolm (2019) “Causal Inference and Data-Fusion in Econometrics” (arXiv)
    • My causal diagrams cheat sheet and lectures for 305

What is a Cause?

All of this is dependent on the idea of one variable causing another? So what’s our working definition of that?

It’s based on the do-operator from the do-calculus. Iff we could set the value of a variable X, and as a result Y changes, then X causes Y.

Causal Diagrams

Let’s make some models!

Building a Diagram

We’re economists, we know this one.

  • Make a list of the variables likely to be relevant in the system
  • Be parsimonious
  • Include unobservable/unmeasurable variables, label them as such
  • Draw arrows from causes (“ancestors” - this is graph theory remember) to caused (“children”)
  • Two variables are correlated but neither causes the other? Must be a shared cause! Either add an unobserved variable, say U1, and have it cause both, or have a double-headed arrow between them (but this may be confused for “they cause each other”).

Example - Effect of Police on Crime

What variables are likely in the DGP for crime? (simplified)

  • Crime
  • Number of police
  • Lagged crime
  • Sentencing rules
  • Profitability of crime (observable?)
  • Law-and-order politics (observable?)

Example - Effect of Police on Crime

What causes what?

  • Crime: our outcome
  • Number of police: causes crime, profitability
  • Lagged crime: causes crime, num police, sentencing
  • Sentencing rules: causes profitability
  • Profitability of crime: causes crime
  • Law-and-order politics: causes police, sentencing

Example - Effect of Police on Crime

So Far

  • Drawing something like this gives us a great opportunity to talk about model building
  • Can we think of things that might be left out of the graph? Are those important?
  • Do we believe all the arrows that are there? Do we believe all the arrows that are not there (effectively exclusion restrictions of a sort!)
  • Our assumptions are very transparent, including between covariates

Potential Issues

  • What about cycles? Plenty of feedback loops in econ, but you can’t identify anything with a cycle (also true in PO by the way)
  • One way to deal is to introduce time. \(A \rightarrow B\) AND \(B \rightarrow A\)? No! \(A_{t-1} \rightarrow B_t\) and \(B_{t-1} \rightarrow A_t\)
  • Simultaneous equations is tricker - tbh there’s still not a great agreed-upon solution for how to model supply and demand here

Now What?

  • Now that we have our diagram (let’s assume it’s correct for funsies) we can think about identification
  • The steps to identification are very simple:
    1. Write all paths that go from treatment to outcome.
    2. Determine which paths we want to be part of our estimated effect (“front door” paths) and which we don’t (“back door”)
    3. Identify only the paths of interest via (i) “blocking back door paths” via adjustment of observed variables, (ii) instrument (broadly defined), or (iii) rarely, the “front door method”

Identification by Adjustment

Paths from Police to Crime

  • Police \(\rightarrow\) Crime
  • Police \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\rightarrow\) Profit \(\leftarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime

Labeling Paths

  • Police \(\rightarrow\) Crime “Direct effect”
  • Police \(\rightarrow\) Profit \(\rightarrow\) Crime “Indirect effect”
  • Police \(\rightarrow\) Profit \(\leftarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime

Front doors”! These are the effects we’re interested in. Rules for picking these may vary depending on research Q (maybe the second doesn’t count!)

Labeling Paths

  • Police \(\rightarrow\) Crime
  • Police \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\rightarrow\) Profit \(\leftarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime
Front doors
Open back doors

Closed doors (back to this in a bit)

How do we Teach with Paths?

This paths approach does a few things pedagogically:

  • It really clearly gets across what identification is. We’re trying to make sure that our estimate can be identified as being associated only with the paths of interest
  • It shows much more precisely what correlation != causation means. If we just do cor(Police,Crime) we get the effects we want, but ALSO all the effects that go along the back door paths. This is both more precise and more intuitive than “OVB is from variables related to both treatment and outcome”. We are interested only in the part of the correlation that we can identify as being due to our front door paths.
  • It makes clear things like post-treatment bias. Why not control for profit? It’s clearly a determinant of crime! But it’s on a front door path - we WANT that effect!

Identifying by Controls

  • We can identify the effect of interest through controls/adjustment by closing all the back-door paths without closing any front-door paths.
  • (And remember, “controlling” could be by regression, by matching, by selecting a sample with no variation in the control variable)
  • Whenever we control for a variable, it closes any path that has that variable on it
  • Don’t forget: can’t control for something if it’s unobserved!

Our Paths

  • Police \(\rightarrow\) Crime
  • Police \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\rightarrow\) Profit \(\leftarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime
Front doors
Open back doors

Closed doors

Our Paths

Controlling for L.Crime

  • Police \(\rightarrow\) Crime
  • Police \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\rightarrow\) Profit \(\leftarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime
Front doors
Open back doors

Closed doors

Our Paths

Controlling for L.Crime and LawOrd

  • Police \(\rightarrow\) Crime
  • Police \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\rightarrow\) Profit \(\leftarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Crime
  • Police \(\leftarrow\) L.Crime \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\rightarrow\) Profit \(\rightarrow\) Crime
  • Police \(\leftarrow\) LawOrd \(\rightarrow\) Sntnc \(\leftarrow\) L.Crime \(\rightarrow\) Crime
Front doors
Open back doors

Closed doors

Colliders

  • Why were the third and last paths purple from the start?
  • And why close the second-to-last path with LawOrd instead of Sntnc?
  • A variable is a collider on a particular path if the arrows on either side of it both point at it (the arrows collide)
  • A path is automatically closed if there’s a collider on it, no adjustment needed
  • But if you DO adjust for the collider, it OPENS BACK UP
  • In our case Sntnc would have still been fine since we’d close that last path back down again with L.Crime, but still

Huh?

  • Yes, really! If we have A \(\rightarrow\) C \(\leftarrow\) B, then A and B are unrelated to each other
  • Imagine partnering for childbirth was random. Mom & dad would have unrelated eye color, but both MomEyes and DadEyes would cause KidEyes
  • So if we’re interested in the effect of MomEyes \(\rightarrow\) DadEyes (real effect 0), MomEyes \(\rightarrow\) KidEyes \(\leftarrow\) DadEyes is a back door path but it doesn’t bias us, cor(MomEyes,DadEyes) = 0 without adjustment
  • But controlling for KidEyes biases us! Among kids with brown eyes, moms with blue eyes have kids with brown-eyed dads. MomEyes appears to cause DadEyes
  • Similar to econometrics idea of selection bias a bit

Another Example

  • We want to know if computer skills cause your social skills to drop
  • Assume true effect is 0
  • We want to test this, so we test a bunch of people at a tech company on both their computer skills and social skills
  • However, to get hired in the first place, you need some minimum mixture of computer and/or social skills!

Another Example

True relationship is 0…

Another Example

Just interviewing tech workers is similar to “controlling for tech”

Collider Bias

  • It does pop up in real life, quite a bit! Economists don’t know to look for it. I’ve corrected for it in one of my own papers and called it out in referee reports, for example on studies using data on college graduates to look at the effect of one in-college experience on another
  • Or… did you know that among NBA players, height doesn’t affect basketball skill?

## List of 65
##  $ line                      :List of 6
##   ..$ colour       : chr "black"
##   ..$ size         : num 0.5
##   ..$ linetype     : num 1
##   ..$ lineend      : chr "butt"
##   ..$ arrow        : logi FALSE
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_line" "element"
##  $ rect                      :List of 5
##   ..$ fill         : chr "white"
##   ..$ colour       : chr "black"
##   ..$ size         : num 0.5
##   ..$ linetype     : num 1
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_rect" "element"
##  $ text                      :List of 11
##   ..$ family       : chr ""
##   ..$ face         : chr "plain"
##   ..$ colour       : chr "black"
##   ..$ size         : num 11
##   ..$ hjust        : num 0.5
##   ..$ vjust        : num 0.5
##   ..$ angle        : num 0
##   ..$ lineheight   : num 0.9
##   ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 0pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : logi FALSE
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.title.x              :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : NULL
##   ..$ vjust        : num 1
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 2.75pt 0pt 0pt 0pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.title.x.top          :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : NULL
##   ..$ vjust        : num 0
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 0pt 0pt 2.75pt 0pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.title.y              :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : NULL
##   ..$ vjust        : num 1
##   ..$ angle        : num 90
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 0pt 2.75pt 0pt 0pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.title.y.right        :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : NULL
##   ..$ vjust        : num 0
##   ..$ angle        : num -90
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 2.75pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.text                 :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : chr "grey30"
##   ..$ size         : 'rel' num 0.8
##   ..$ hjust        : NULL
##   ..$ vjust        : NULL
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : NULL
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.text.x               :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : NULL
##   ..$ vjust        : num 1
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 2.2pt 0pt 0pt 0pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.text.x.top           :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : NULL
##   ..$ vjust        : num 0
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 0pt 0pt 2.2pt 0pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.text.y               :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : num 1
##   ..$ vjust        : NULL
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 0pt 2.2pt 0pt 0pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.text.y.right         :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : num 0
##   ..$ vjust        : NULL
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 2.2pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.ticks                : list()
##   ..- attr(*, "class")= chr [1:2] "element_blank" "element"
##  $ axis.ticks.length         : 'unit' num 2.75pt
##   ..- attr(*, "valid.unit")= int 8
##   ..- attr(*, "unit")= chr "pt"
##  $ axis.ticks.length.x       : NULL
##  $ axis.ticks.length.x.top   : NULL
##  $ axis.ticks.length.x.bottom: NULL
##  $ axis.ticks.length.y       : NULL
##  $ axis.ticks.length.y.left  : NULL
##  $ axis.ticks.length.y.right : NULL
##  $ axis.line                 : list()
##   ..- attr(*, "class")= chr [1:2] "element_blank" "element"
##  $ axis.line.x               : NULL
##  $ axis.line.y               : NULL
##  $ legend.background         : list()
##   ..- attr(*, "class")= chr [1:2] "element_blank" "element"
##  $ legend.margin             : 'margin' num [1:4] 5.5pt 5.5pt 5.5pt 5.5pt
##   ..- attr(*, "valid.unit")= int 8
##   ..- attr(*, "unit")= chr "pt"
##  $ legend.spacing            : 'unit' num 11pt
##   ..- attr(*, "valid.unit")= int 8
##   ..- attr(*, "unit")= chr "pt"
##  $ legend.spacing.x          : NULL
##  $ legend.spacing.y          : NULL
##  $ legend.key                : list()
##   ..- attr(*, "class")= chr [1:2] "element_blank" "element"
##  $ legend.key.size           : 'unit' num 1.2lines
##   ..- attr(*, "valid.unit")= int 3
##   ..- attr(*, "unit")= chr "lines"
##  $ legend.key.height         : NULL
##  $ legend.key.width          : NULL
##  $ legend.text               :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : 'rel' num 0.8
##   ..$ hjust        : NULL
##   ..$ vjust        : NULL
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : NULL
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ legend.text.align         : NULL
##  $ legend.title              :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : num 0
##   ..$ vjust        : NULL
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : NULL
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ legend.title.align        : NULL
##  $ legend.position           : chr "right"
##  $ legend.direction          : NULL
##  $ legend.justification      : chr "center"
##  $ legend.box                : NULL
##  $ legend.box.margin         : 'margin' num [1:4] 0cm 0cm 0cm 0cm
##   ..- attr(*, "valid.unit")= int 1
##   ..- attr(*, "unit")= chr "cm"
##  $ legend.box.background     : list()
##   ..- attr(*, "class")= chr [1:2] "element_blank" "element"
##  $ legend.box.spacing        : 'unit' num 11pt
##   ..- attr(*, "valid.unit")= int 8
##   ..- attr(*, "unit")= chr "pt"
##  $ panel.background          : list()
##   ..- attr(*, "class")= chr [1:2] "element_blank" "element"
##  $ panel.border              : list()
##   ..- attr(*, "class")= chr [1:2] "element_blank" "element"
##  $ panel.spacing             : 'unit' num 5.5pt
##   ..- attr(*, "valid.unit")= int 8
##   ..- attr(*, "unit")= chr "pt"
##  $ panel.spacing.x           : NULL
##  $ panel.spacing.y           : NULL
##  $ panel.grid                :List of 6
##   ..$ colour       : chr "grey92"
##   ..$ size         : NULL
##   ..$ linetype     : NULL
##   ..$ lineend      : NULL
##   ..$ arrow        : logi FALSE
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_line" "element"
##  $ panel.grid.minor          :List of 6
##   ..$ colour       : NULL
##   ..$ size         : 'rel' num 0.5
##   ..$ linetype     : NULL
##   ..$ lineend      : NULL
##   ..$ arrow        : logi FALSE
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_line" "element"
##  $ panel.ontop               : logi FALSE
##  $ plot.background           : list()
##   ..- attr(*, "class")= chr [1:2] "element_blank" "element"
##  $ plot.title                :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : 'rel' num 1.2
##   ..$ hjust        : num 0
##   ..$ vjust        : num 1
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 0pt 0pt 5.5pt 0pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ plot.subtitle             :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : num 0
##   ..$ vjust        : num 1
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 0pt 0pt 5.5pt 0pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ plot.caption              :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : 'rel' num 0.8
##   ..$ hjust        : num 1
##   ..$ vjust        : num 1
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 5.5pt 0pt 0pt 0pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ plot.tag                  :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : 'rel' num 1.2
##   ..$ hjust        : num 0.5
##   ..$ vjust        : num 0.5
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : NULL
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ plot.tag.position         : chr "topleft"
##  $ plot.margin               : 'margin' num [1:4] 5.5pt 5.5pt 5.5pt 5.5pt
##   ..- attr(*, "valid.unit")= int 8
##   ..- attr(*, "unit")= chr "pt"
##  $ strip.background          : list()
##   ..- attr(*, "class")= chr [1:2] "element_blank" "element"
##  $ strip.placement           : chr "inside"
##  $ strip.text                :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : chr "grey10"
##   ..$ size         : 'rel' num 0.8
##   ..$ hjust        : NULL
##   ..$ vjust        : NULL
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : 'margin' num [1:4] 4.4pt 4.4pt 4.4pt 4.4pt
##   .. ..- attr(*, "valid.unit")= int 8
##   .. ..- attr(*, "unit")= chr "pt"
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ strip.text.x              : NULL
##  $ strip.text.y              :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : NULL
##   ..$ vjust        : NULL
##   ..$ angle        : num -90
##   ..$ lineheight   : NULL
##   ..$ margin       : NULL
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ strip.switch.pad.grid     : 'unit' num 2.75pt
##   ..- attr(*, "valid.unit")= int 8
##   ..- attr(*, "unit")= chr "pt"
##  $ strip.switch.pad.wrap     : 'unit' num 2.75pt
##   ..- attr(*, "valid.unit")= int 8
##   ..- attr(*, "unit")= chr "pt"
##  - attr(*, "class")= chr [1:2] "theme" "gg"
##  - attr(*, "complete")= logi TRUE
##  - attr(*, "validate")= logi TRUE

Anyway!

  • With all that in mind, as long as we can write out the paths and select a set of controls that closes all back doors
  • Adding a control is like deleting all arrows leading away from that variable
  • Pedagogic bonus points: this naturally forces us to ask if we can actually control for those (is the diagram complete? Is there anything missing that would be on a back door? Can we actually measure all these variables? If “SES” is on a back door can we really control for all of that?)

Fixed Effects

Identifying by adjustment isn’t limited to selection-on-observables. For example, when does fixed effects work? When the diagram looks like this (after removing any other controlled variables):

Where Indiv is any individual effect that is fixed over time

Event Study

When does an event study work? When the diagram looks like this

Difference-in-Difference / Synthetic Control

If we think there’s a time effect as well, we either need to account for it with time-series dependencies in an event study, or add a control group so we can directly control for time in DID/Synth

Identification by Instrument

Identifying by Instrument

  • But identifying by adjustment isn’t our only option!
  • You can also isolate the part of the variation in one variable \(X\) related to variation in another \(Z\)
  • In doing so, you eliminate any back doors to \(X\) that aren’t also back doors to \(Z\)
  • This identifies \(X\rightarrow Y\) if all open paths from \(Z\) to \(Y\) go through \(X\) (i.e., validity!)
  • This shows you (i) why IVs are like experiments, (ii) why you can use IV to estimate the effects of experiments with imperfect assignment, and (iii) why you include controls in your first stage

Randomized Experiments

Instrumental Variables

Instrumental Variables with Controls

This works if you control for V

Regression Discontinuity

Controlling for Run, Above is an IV for Treat (RD relies on a functional form restriction, so this one’s a bit cheaty!)

Front-Door Method

  • Applications for this one are so far just about nil, but maybe someday…
  • For now this can probably be skipped in UG
  • But basically, imagine \(W\) is unmeasurable. You can identify \(X \rightarrow Z\) and \(Z \rightarrow Y\), then put them together to get \(X \rightarrow Z \rightarrow Y\). Hooray!

Front-Door Method

Say we only want the indirect effect and L.Crime is unmeasurable. Control for Sntnc or LawOrd to get Police \(\rightarrow\) Profit, and control for Police and Sntnc to get Profit \(\rightarrow\) Crime. Combine to get effect.

Bonus!

One Last Thing…

  • A neat thing about causal diagrams is that they lend themselves very well to placebo tests
  • Generally, the structure of the diagram will suggest relationships that shouldn’t exist
  • If they do exist, the model is wrong!

For Example:

All paths between LawOrd and L.Crime have colliders. If their raw relationship is nonzero, this model is wrong!

For Example:

Do we have serial correlation?

Teaching with Causal Diagrams

Conclusion and Logistics

Using Causal Diagrams

  • Whether causal diagrams are going to be, like, the way we do applied economics from now on, that’s up in the air. I think they’re very handy, but the marginal value-added when you already know PO is honestly not huge
  • Plus, the question of “should this be how you do research” brings back all the same pros and cons of the structural vs. reduced form debate
  • But pedagogically? This stuff is untouchable. Students get it
  • And it makes easy and apparent a bunch of stuff we’ve been teaching as arcane and technical
  • Students can even figure out intuitively the research designs of complex published papers, even without understanding the technical details

Drawing Causal Diagrams

So if you’re sold, how do you actually make these things?

  1. Draw them on the board
  2. Use dagitty and ggdag in R
  3. Use the dagitty website dagitty.net

In R

  • I’ve made the diagrams you’ve seen today directly in R
  • Unless you are doing slides in RMarkdown and don’t want to bother saving image files from the dagitty website, I wouldn’t really recommend it
  • Doesn’t look as nice, and is harder to make
  • The package is more designed for if you’re doing research with DAGs
  • I copy/paste the code every time and just fill in
  • If on Windows, be sure to also use the Cairo package and set dev='CairoPNG' in your code chunk

In R

library(dagitty); library(ggdag)
dag <- dagify(Y2~Y1+Shock2,
              Y1~Shock1,
              coords=list(
                x = c(Y1 = 1, Shock1 = 1.5, Y2 = 1.5, Shock2 = 2),
                y = c(Y1 = 2, Shock1 = 2.5, Y2 = 1.5, Shock2 = 2)
              )) %>% tidy_dagitty()
ggdag(dag,node_size=20)+theme_void()

Dagitty.net

  • Dagitty.net is very nice!
  • Students can use it too
  • Works on mobile, as of most recent update
  • Color-coded diagrams
  • Finds adjustment sets and IVs for you, as well as testable model implications (that may make it hard to use it for homework assignments)
  • Let’s go look at it and explore. Also see my beginner’s guide on their Learn page.

That’s it!

  • I hope you found some value in this
  • And will give it a shot in your classroom
  • If we have time, let’s DAGify a classic paper, perhaps an Angrist?