12.3 Statistical inference
12.3.1 Inference about the direct effect.
We’ve already computed the 95% intervals for these. Here they are as stat_pointinterval()
plots.
post %>%
select(starts_with("direct")) %>%
gather() %>%
mutate(key = str_remove(key, "direct effect when W is ") %>% as.double()) %>%
ggplot(aes(x = key, y = value, group = key)) +
stat_pointinterval(point_interval = median_qi, .prob = c(.95, .5)) +
coord_cartesian(xlim = c(1, 5.5)) +
labs(x = expression(paste("Climate Change Skepticism (", italic(W), ")")),
y = "Conditional Direct Effect of Disaster Frame on\nWillingness to Donate")
12.3.2 Inference about the indirect effect.
12.3.2.1 A statistical test of moderated mediation.
To get a sense of \(a_{3}b\), we just:
post <-
post %>%
mutate(a3b = `b_justify_frame:skeptic`*b_donate_justify)
post %>%
select(a3b) %>%
summarize(median = median(a3b),
sd = sd(a3b),
ll = quantile(a3b, probs = .025),
ul = quantile(a3b, probs = .975)) %>%
mutate_if(is.double, round, digits = 3)
## median sd ll ul
## 1 -0.182 0.055 -0.295 -0.082
We might use stat_pointintervalh()
to visualize \(a_{3}b\) with a coefficient plot.
post %>%
ggplot(aes(x = a3b, y = 1)) +
stat_pointintervalh(point_interval = median_qi, .prob = c(.95, .5)) +
scale_y_discrete(NULL, breaks = NULL) +
coord_cartesian(xlim = c(-.5, 0)) +
labs(title = expression(paste("Coefficient plot for ", italic(a)[3], italic(b), " (i.e., the index of moderated mediation)")),
x = NULL)
12.3.2.2 Probing moderation of mediation.
As discussed in my manuscript for Chapter 11, our Bayesian version of the JN technique should be fine because HMC does not impose the normality assumption on the parameter posteriors. In this instance, I’ll leave the JN technique plot as an exercise for the interested reader. Here we’ll just follow along with the text and pick a few points.
We computed and inspected these 95% intervals, above. Here we look at the entire densities with geom_halfeyeh()
.
post %>%
select(starts_with("indirect")) %>%
gather() %>%
rename(`indirect effect` = value) %>%
mutate(W = str_remove(key, "indirect effect when W is ") %>% as.double()) %>%
ggplot(aes(x = `indirect effect`, y = W, fill = W %>% as.character())) +
geom_halfeyeh(point_interval = median_qi, .prob = c(0.95, 0.5)) +
scale_fill_brewer() +
scale_y_continuous(breaks = c(1.592, 2.8, 5.2),
labels = c(1.6, 2.8, 5.2)) +
coord_cartesian(xlim = -1:1) +
theme(legend.position = "none",
panel.grid.minor.y = element_blank())
12.3.3 Pruning the model.
Fitting the model without the interaction term is just a small change to one of our formula
arguments.
model4 <-
brm(data = disaster, family = gaussian,
bf(justify ~ 1 + frame + skeptic + frame:skeptic) +
bf(donate ~ 1 + frame + justify + skeptic) +
set_rescor(FALSE),
chains = 4, cores = 4)
Here are the results.
print(model4, digits = 3)
## Family: MV(gaussian, gaussian)
## Links: mu = identity; sigma = identity
## mu = identity; sigma = identity
## Formula: justify ~ 1 + frame + skeptic + frame:skeptic
## donate ~ 1 + frame + justify + skeptic
## Data: disaster (Number of observations: 211)
## Samples: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
## total post-warmup samples = 4000
##
## Population-Level Effects:
## Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
## justify_Intercept 2.454 0.149 2.161 2.745 3240 1.001
## donate_Intercept 7.258 0.234 6.813 7.726 4000 1.000
## justify_frame -0.565 0.219 -1.003 -0.144 2774 1.002
## justify_skeptic 0.105 0.038 0.033 0.180 3178 1.001
## justify_frame:skeptic 0.202 0.056 0.094 0.311 2568 1.003
## donate_frame 0.208 0.143 -0.071 0.488 4000 0.999
## donate_justify -0.918 0.083 -1.083 -0.759 4000 1.000
## donate_skeptic -0.037 0.037 -0.109 0.037 4000 1.000
##
## Family Specific Parameters:
## Estimate Est.Error l-95% CI u-95% CI Eff.Sample Rhat
## sigma_justify 0.818 0.040 0.744 0.900 4000 1.000
## sigma_donate 0.986 0.050 0.896 1.091 4000 1.000
##
## Samples were drawn using sampling(NUTS). For each parameter, Eff.Sample
## is a crude measure of effective sample size, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
Since we’re altering the model, we may as well use information criteria to compare the two versions.
loo(model3, model4)
## LOOIC SE
## model3 1117.48 33.12
## model4 1115.41 33.13
## model3 - model4 2.07 0.53
The difference in LOO-CV values for the two models was modest. There’s little predictive reason to choose one over the other. You could argue that model4
is simpler than model3
. Since we’ve got a complex model either way, one might also consider which one was of primary theoretical interest.