swh:1:snp:cf20732a2a91717cec7759cd75c5d1a72600b018
Tip revision: 6acd4f1707b182a2cbe2f4a4c2d4196571d36eb3 authored by Dominique Makowski on 05 December 2020, 08:30:02 UTC
version 0.8.0
version 0.8.0
Tip revision: 6acd4f1
mediation.Rmd
---
title: "Summary of Mediation Analysis using Bayesian Regression Models"
output:
github_document:
toc: true
fig_width: 10.08
fig_height: 6
rmarkdown::html_vignette:
toc: true
fig_width: 10.08
fig_height: 6
tags: [r, bayesian, posterior, mediation]
vignette: >
\usepackage[utf8]{inputenc}
%\VignetteIndexEntry{Mediation Analysis using Bayesian Regression Models}
%\VignetteEngine{knitr::rmarkdown}
editor_options:
chunk_output_type: console
bibliography: bibliography.bib
csl: apa.csl
---
```{r, SETTINGS-knitr, echo = FALSE, warning = FALSE, message = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
dev = "png",
fig.width = 7,
fig.height = 5,
message = FALSE,
warning = FALSE
)
options(width = 800)
if (!requireNamespace("mediation", quietly = TRUE) ||
!requireNamespace("httr", quietly = TRUE) ||
!requireNamespace("lavaan", quietly = TRUE) ||
!requireNamespace("brms", quietly = TRUE) ||
!requireNamespace("rstanarm", quietly = TRUE) ||
!requireNamespace("insight", quietly = TRUE)) {
knitr::opts_chunk$set(eval = FALSE)
}
```
This vignettes demonstrates the `mediation()`-function. Before we start, we fit some models, including a mediation-object from the _mediation_-package and a structural equation modelling approach with the _lavaan_-package, both of which we use for comparison with _brms_ and _rstanarm_.
## Mediation Analysis in brms and rstanarm
```{r}
library(bayestestR)
library(mediation)
library(brms)
library(rstanarm)
# load sample data
data(jobs)
set.seed(123)
# linear models, for mediation analysis
b1 <- lm(job_seek ~ treat + econ_hard + sex + age, data = jobs)
b2 <- lm(depress2 ~ treat + job_seek + econ_hard + sex + age, data = jobs)
# mediation analysis, for comparison with brms
m1 <- mediate(b1, b2, sims = 1000, treat = "treat", mediator = "job_seek")
```
```{r eval=FALSE}
# Fit Bayesian mediation model in brms
f1 <- bf(job_seek ~ treat + econ_hard + sex + age)
f2 <- bf(depress2 ~ treat + job_seek + econ_hard + sex + age)
m2 <- brm(f1 + f2 + set_rescor(FALSE), data = jobs, cores = 4)
```
```{r echo=FALSE}
m2 <- insight::download_model("brms_mv_6")
```
```{r eval=FALSE}
# Fit Bayesian mediation model in rstanarm
m3 <- stan_mvmer(
list(job_seek ~ treat + econ_hard + sex + age + (1 | occp),
depress2 ~ treat + job_seek + econ_hard + sex + age + (1 | occp)),
data = jobs,
cores = 4,
refresh = 0
)
```
```{r echo=FALSE}
m3 <- insight::download_model("stanmvreg_2")
```
`mediation()` is a summary function, especially for mediation analysis, i.e. for multivariate response models with casual mediation effects.
In the models `m2` and `m3`, `treat` is the treatment effect and `job_seek` is the mediator effect. For the *brms* model (`m2`), `f1` describes the mediator model and `f2` describes the outcome model. This is similar for the *rstanarm* model.
`mediation()` returns a data frame with information on the _direct effect_ (median value of posterior samples from treatment of the outcome model), _mediator effect_ (median value of posterior samples from mediator of the outcome model), _indirect effect_ (median value of the multiplication of the posterior samples from mediator of the outcome model and the posterior samples from treatment of the mediation model) and the _total effect_ (median value of sums of posterior samples used for the direct and indirect effect). The _proportion mediated_ is the indirect effect divided by the total effect.
The simplest call just needs the model-object.
```{r, message=TRUE}
# for brms
mediation(m2)
# for rstanarm
mediation(m3)
```
Typically, `mediation()` finds the treatment and mediator variables automatically. If this does not work, use the `treatment` and `mediator` arguments to specify the related variable names. For all values, the 89% credible intervals are calculated by default. Use `ci` to calculate a different interval.
## Comparison to the mediation package
Here is a comparison with the _mediation_ package. Note that the `summary()`-output of the _mediation_ package shows the indirect effect first, followed by the direct effect.
```{r}
summary(m1)
mediation(m2, ci = .95)
mediation(m3, ci = .95)
```
If you want to calculate mean instead of median values from the posterior samples, use the `centrality`-argument. Furthermore, there is a `print()`-method, which allows to print more digits.
```{r, message=TRUE}
m <- mediation(m2, centrality = "mean", ci = .95)
print(m, digits = 4)
```
As you can see, the results are similar to what the _mediation_ package produces for non-Bayesian models.
## Comparison to SEM from the lavaan package
Finally, we also compare the results to a SEM model, using *lavaan*. This example should demonstrate how to "translate" the same model in different packages or modeling approached.
```{r}
library(lavaan)
data(jobs)
set.seed(1234)
model <- ' # direct effects
depress2 ~ c1*treat + c2*econ_hard + c3*sex + c4*age + b*job_seek
# mediation
job_seek ~ a1*treat + a2*econ_hard + a3*sex + a4*age
# indirect effects (a*b)
indirect_treat := a1*b
indirect_econ_hard := a2*b
indirect_sex := a3*b
indirect_age := a4*b
# total effects
total_treat := c1 + (a1*b)
total_econ_hard := c2 + (a2*b)
total_sex := c3 + (a3*b)
total_age := c4 + (a4*b)
'
m4 <- sem(model, data = jobs)
summary(m4)
# just to have the numbers right at hand and you don't need to scroll up
mediation(m2, ci = .95)
```
The summary output from *lavaan* is longer, but we can find the related numbers quite easily:
- the _direct effect_ of treatment is `treat (c1)`, which is `-0.040`
- the _indirect effect_ of treatment is `indirect_treat`, which is `-0.016`
- the _mediator effect_ of job_seek is `job_seek (b)`, which is `-0.240`
- the _total effect_ is `total_treat`, which is `-0.056`