# Confounder choice to minimize variance in causal estimate

Let's imagine we have data generated according to the DAG

X  ->  y  <- U2
^      ^
|      |
U0 -> U1

I was running some simulations (below) to work on my intuition and I had some questions about selection control variables in a model in order to reduce the variance of the causal estimate of $$X$$ in $$y$$

The models \begin{align} &m_0\!: &&y \sim X + U_0 \\ &m_{01}\!: &&y \sim X + U_0 + U_1 \\ &m_1\!: &&y \sim X + U_1 \\ &m_{12}\!: &&y \sim X + U_1 + U_2 \end{align} All give an unbiased estimate of the causal effect of $$X$$ on $$y$$, however, in terms of the variance of the estimate, we have

$$m_{12} \lt m_1 \lt m_{01} \lt m_0$$

My observations are that conditional on the backdoor paths being blocked, controlling for variables "adjacent" to $$y$$ is better than controlling for variables farther away from $$y$$ and that controlling for multiple variable on a backdoor path is worse than only controlling for the variable ($$m_{01}$$ vs $$m_1$$)

I was wondering what the explanation for these phenomena is? It seems that DAGs can be very useful for this sort of model selection/experimental design but I haven't really found any DAG based resources.

library(dplyr)
library(broom)
# library(ggplot2)

n_sims <- 1000
n <- 100

simulate <- function(){
u0 <-  rnorm(n)
x <- u0 + rnorm(n, sd=0.5)
u1 <- u0 + rnorm(n, sd=0.5)
u2 <- rnorm(n)
y <- x + u1 + u2 +  rnorm(n)

models <- list(
m0 =lm(y ~ x + u0 ),
m1 = lm(y ~ x + u1),
m12 = lm(y ~ x + u1 + u2),
m01 = lm(y ~ x + u0 + u1)
)

bind_rows(lapply(models, tidy), .id = 'model')
}

results <-
replicate(n_sims, simulate(), simplify = FALSE) %>%
bind_rows(.id = 'iter')
#
# results %>%
#   filter(term == 'x') %>%
#   ggplot() +
#   geom_histogram(aes(estimate)) +
#   facet_wrap(~model)

results %>%
filter(term == 'x') %>%
group_by(model, term) %>%
summarise(var(estimate))
#> summarise() has grouped output by 'model'.
#>               You can override using the .groups argument.
#> # A tibble: 4 × 3
#> # Groups:   model [4]
#>   model term  var(estimate)
#>   <chr> <chr>           <dbl>
#> 1 m0    x              0.0923
#> 2 m01   x              0.0819
#> 3 m1    x              0.0452
#> 4 m12   x              0.0231

Created on 2022-01-16 by the reprex package (v2.0.1)

• Please consider using base R, & commenting it extensively, when illustrating posts here with R code. Not everyone who will come to this page will be familiar with R, & not all of those will be able to read tidy-code. This is a Q&A site for statistics, not R. Jan 17 at 18:43