Multiple regression is no oracle, but only a golem. It is logical, but the relationships it describes are conditional associations, not causal influences. Therefore additional information, from outside the model, is needed to make sense of it. This chapter presented introductory examples of some common frustrations: multicollinearity, post-treatment bias, and collider bias. Solutions to these frustrations can be organized under a coherent framework in which hypothetical causal relations among variables are analyzed to cope with confounding. In all cases, causal models exist outside the statistical model and can be difficult to test. However, it is possible to reach valid causal inferences in the absence of experiments. This is good news, because we often cannot perform experiments, both for practical and ethical reasons.
Place each answer inside the code chunk (grey box). The code chunks should contain a text response or a code that completes/answers the question or activity requested. Problems are labeled Easy (E), Medium (M), and Hard(H).
Finally, upon completion, name your final output .html file as: YourName_ANLY505-Year-Semester.html and publish the assignment to your R Pubs account and submit the link to Canvas. Each question is worth 5 points.
6E1. List three mechanisms by which multiple regression can produce false inferences about causal effects.
multicollinearity, post-treatment bias, and collider bias
6E2. For one of the mechanisms in the previous problem, provide an example of your choice, perhaps from your own research.
multicollinearity exists when two or more of the predictors in a regression model are moderately or highly correlated with one another.
An example would be using age and price of the cars to predict auto insurance premium - one predictor can be used to predict the other, therefore the result/prediction is skewed.
6E3. List the four elemental confounds. Can you explain the conditional dependencies of each?
The four elements are: 1. Fork. 2. Pipe. 3. Collider. 4. Descendent.
Fork: X<-Z->Y. X and Y are independent, conditional on Z. This is the classic confounder. In a fork, some variable Z is a common cause of X and Y, generating a correlation between them. If we condition on Z, then learning X tells us nothing about Y
Pipe: X->Z->Y. If we condition on Z now, we also block the path from X to Y. So in both a fork and a pipe, conditioning of the middle variable blocks the path
Collider: X->Z<-Y. Unlike the other two types of relations, in a collider there is no association between X and Y unless you condition on Z. Conditioning on Z, the collider variable, opens the path. Once the path is open, information flows between X and Y.
The fourth is that conditioning on a descendent variable is like conditioning on the variable itself, but weaker. A descendent is a variable influenced by another variable.
6E4. How is a biased sample like conditioning on a collider? Think of the example at the open of the chapter.
“It seems like the most newsworthy scientific studies are the least trustworthy. The more likely it is to kill you, if true, the less likely it is to be true. The more boring the topic, the more rigorous the results.”
When conditioning on a collider, in this case - the final score (ranked by combined trustworthiness and newsworthiness), the two criteria are strongly negatively correlated after selection While there is no correlation before selection. Any proposals selected to be fund either needs to be newsworthy or trustworthy. Otherwise, they won’t be funded. It is the selection-distortion effect.
6M1. Modify the DAG on page 186 to include the variable V, an unobserved cause of C and Y: C ← V → Y. Reanalyze the DAG. How many paths connect X to Y? Which must be closed? Which variables should you condition on now?
Besides the direct path, there are four paths from X to Y: 1. X<-U<-A->C<-V->Y, this path contains a fork U<-A->C, a pipe X<-U, and a collider C<-V->Y. 2. X<-U->B<-C<-V->Y, this path contains 2 sets of collider X<-U->B and B<-C<-V; and C<-V->Y. This path is closed of no conditioning on B and V. 3. X<-U<-A->C->Y 4. X<-U->B<-C->Y
3 should be closed because other three have collider. Conditioning on A would suffice.
library(dagitty)
dag_6.1 <- dagitty( "dag {
U [unobserved]
V [unobserved]
X -> Y
X <- U <- A -> C -> Y
U -> B <- C
C <- V -> Y
}")
adjustmentSets( dag_6.1 , exposure="X" , outcome="Y" )
## { A }
6M2. Sometimes, in order to avoid multicollinearity, people inspect pairwise correlations among predictors before including them in a model. This is a bad procedure, because what matters is the conditional association, not the association before the variables are included in the model. To highlight this, consider the DAG X → Z → Y. Simulate data from this DAG so that the correlation between X and Z is very large. Then include both in a model prediction Y. Do you observe any multicollinearity? Why or why not? What is different from the legs example in the chapter?
library(rethinking)
## Loading required package: rstan
## Loading required package: StanHeaders
## Loading required package: ggplot2
## rstan (Version 2.21.2, GitRev: 2e1f913d3ca3)
## For execution on a local, multicore CPU with excess RAM we recommend calling
## options(mc.cores = parallel::detectCores()).
## To avoid recompilation of unchanged Stan programs, we recommend calling
## rstan_options(auto_write = TRUE)
## Do not specify '-march=native' in 'LOCAL_CPPFLAGS' or a Makevars file
## Loading required package: parallel
## rethinking (Version 2.13)
##
## Attaching package: 'rethinking'
## The following object is masked from 'package:stats':
##
## rstudent
N <- 100 # number of individuals
set.seed(909)
x <- rnorm(N,10,2) # sim total
leg_X <- runif(N,0.4,0.5) # leg as proportion
leg_Z <- runif(N,0.4,0.6)
z <- leg_X*x + rnorm( N , 0 , 0.02 ) # sim + error
y <- leg_Z*x + rnorm( N , 0 , 0.02 ) # sim + error
# combine into data frame
d <- data.frame(x,z,y)
cor(d$x,d$z)
## [1] 0.9557877
m6.1 <- quap(
alist(
y ~ dnorm( mu , sigma ) ,
mu <- a + bx*x + bz*z ,
a ~ dnorm( 10 , 100 ) ,
bx ~ dnorm( 2 , 10 ) ,
bz ~ dnorm( 2 , 10 ) ,
sigma ~ dexp( 1 )
) ,
data=d )
precis(m6.1)
## mean sd 5.5% 94.5%
## a 0.08914878 0.25900923 -0.32479799 0.5030956
## bx 0.37782994 0.08599496 0.24039338 0.5152665
## bz 0.23248899 0.17980045 -0.05486685 0.5198448
## sigma 0.53324131 0.03755552 0.47322033 0.5932623
plot(precis(m6.1))
post <- extract.samples(m6.1)
plot( z ~ x , post , col=col.alpha(rangi2,0.1) , pch=16 )