The following packages are used in this section: psych, tibble, and teachingtools. tibble are part of the tidyverse family.
To make sure that the packages used in this section are installed and loaded, run the following code in your console.
For mediation analysis I’m going to give a brief tour the psych package. The psych package isn’t your only option. In fact, you don’t need a special package for doing mediation analysis, and you could in fact do it just by fitting the appropriate regression models. The only tricky thing there would be calculating the bootstrapped confidence intervals, but these can be estimated with a package called mediation. However, this is overly complicated for the casual user of mediation analysis. The psych, in contrast does it all for you and you only have to specify your X, your M, and your Y.
Mediation in the psych is done with the
psych::mediate() function. In it’s simplest form it only requires the name of your X, M, and Y variables, and the name of your data table. To see it at work, we’ll replicate the first example from Hayes (2018)1
In Chapter 3.3 Hayes (2018) introduces a data set from a study by Tal-Or, Cohen, Tsfati, and Gunther (2010).
(participants) read one of two newspaper articles describing an economic crisis that may affect the price and supply of sugar in Israel. Approximately half of the participants (n = 58) were given an article they were told would be appearing on the front page of a major Israeli newspaper (henceforth referred to as the front page condition). The remaining participants (n = 65) were given the same article but were told it would appear in the middle of an economic supplement of this newspaper (referred to here as the interior page condition).
After the participants read the article, they were asked a number of questions about their reactions to the story. Some questions asked par- ticipants how soon they planned on buying sugar and how much they intended to buy. Their responses were aggregated to form an intention to buy sugar measure (REACTION in the data file)
They were also asked questions used to quantify how much they believed that others in the community would be prompted to buy sugar as a result of exposure to the article, a measure of presumed media influence (PMI in the data file).
The aim was to:
estimate the effects of the manipulation (X […], with the front page condition coded 1 and the interior page condition coded 0) on likelihood of buying sugar (Y […]), directly as well as indirectly through presumed media influence (M […])
Let use try and replicate this analysis with
First, we’ll take a look at our data table called
# A tibble: 123 x 6 cond pmi import reaction gender age <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 1 7 6 5.25 1 51 2 0 6 1 1.25 1 40 3 1 5.5 6 5 1 26 4 0 6.5 6 2.75 0 21 5 0 6 5 2.5 1 27 6 0 5.5 1 1.25 1 25 7 0 3.5 1 1.5 0 23 8 1 6 6 4.75 1 25 9 0 4.5 6 4.25 1 22 10 0 7 6 6.25 1 24 # … with 113 more rows
The column labelled
cond will be our X, the column labelled
reaction will be our Y, and the column labelled
pmi will be our M. We’ll save the model to
hayes1 <- psych::mediate(x = "cond", # our X y = "reaction", # our Y m = "pmi", # our M data = pmi, # our data table n.iter = 5000, # the number of bootstrap samples (default: 5000) plot = FALSE, # don't draw a plot (default: TRUE) )
To view the model output we can just type in the model name
hayes1 to access this.
Mediation/Moderation Analysis Call: psych::mediate(y = "reaction", x = "cond", m = "pmi", data = pmi, n.iter = 5000, plot = FALSE) The DV (Y) was reaction . The IV (X) was cond . The mediating variable(s) = pmi . Total effect(c) of cond on reaction = 0.5 S.E. = 0.28 t = 1.79 df= 122 with p = 0.075 Direct effect (c') of cond on reaction removing pmi = 0.25 S.E. = 0.55 t = 0.96 df= 120 with p = 0.34 Indirect effect (ab) of cond on reaction through pmi = 0.24 Mean bootstrapped indirect effect = 0.24 with standard error = 0.13 Lower CI = 0 Upper CI = 0.52 R = 0.45 R2 = 0.21 F = 15.56 on 2 and 120 DF p-value: 1.31e-08 To see the longer output, specify short = FALSE in the print statement or ask for the summary
The model output will give us the statistics for the Total effect, the Direct effect, and the Indirect effect, including the bootstrapped confidence intervals for the Indirect effect.
Another way to access the information about the model is to use the generic function
Call: psych::mediate(y = "reaction", x = "cond", m = "pmi", data = pmi, n.iter = 5000, plot = FALSE) Direct effect estimates (traditional regression) (c') reaction se t df Prob Intercept 0.53 0.55 0.96 120 3.40e-01 cond 0.25 0.26 0.99 120 3.22e-01 pmi 0.51 0.10 5.22 120 7.66e-07 R = 0.45 R2 = 0.21 F = 15.56 on 2 and 120 DF p-value: 9.83e-07 Total effect estimates (c) reaction se t df Prob cond 0.5 0.28 1.79 122 0.0754 'a' effect estimates pmi se t df Prob Intercept 5.38 0.16 33.22 121 1.16e-62 cond 0.48 0.24 2.02 121 4.54e-02 'b' effect estimates reaction se t df Prob pmi 0.51 0.1 5.24 121 6.88e-07 'ab' effect estimates (through mediators) reaction boot sd lower upper cond 0.24 0.24 0.13 0 0.52
If we do want to view the model diagram we can use the
mediate.diagram() function. Compare the plot below to the one in Hayes (2018, pg 88) if you’d like.
One big downside of the psych package is that the model object is difficult to work with. For example, let’s say that we just wanted to get the bootstrapped confidence intervals for the indirect effect, and we wanted to save that to a variable. There is unfortunately no straightforward way to do this. However, all the information is saved in a list inside the output object and you could access it by subsetting.
The mean of ab
The sd of ab
The bootstrapped CIs of ab
2.5% 97.5% 0.003656523 0.523096406
Another big downside of the psych package is that it isn’t that great beyond simple examples like the one I’ve demonstrated. However, if you’re just interested in doing simple mediation, then the psych package might be a more user friendly alternative to the SPSS
For more complex scenarios the go to package is lavaan. lavaan is a package for doing SEM but obviously it can also do simple mediation analysis. However, covering lavaan would take a workshop in itself because the syntax and approach is a lot more complex. Below, just for an illustration, I’ve included an example of how to replicate with lavaan what we did in psych.
xfun::pkg_attach2("lavaan") model <- ' # direct effect reaction ~ c*cond # mediator pmi ~ a*cond reaction ~ b*pmi # indirect effect (a*b) ab := a*b # total effect total := c + (a*b) ' fit <- lavaan::sem(model = model, data = pmi, se = "bootstrap") summary(fit)
lavaan 0.6-6 ended normally after 21 iterations Estimator ML Optimization method NLMINB Number of free parameters 5 Number of observations 123 Model Test User Model: Test statistic 0.000 Degrees of freedom 0 Parameter Estimates: Standard errors Bootstrap Number of requested bootstrap draws 1000 Number of successful bootstrap draws 986 Regressions: Estimate Std.Err z-value P(>|z|) reaction ~ cond (c) 0.254 0.266 0.957 0.339 pmi ~ cond (a) 0.477 0.232 2.052 0.040 reaction ~ pmi (b) 0.506 0.083 6.104 0.000 Variances: Estimate Std.Err z-value P(>|z|) .reaction 1.893 0.201 9.441 0.000 .pmi 1.675 0.289 5.788 0.000 Defined Parameters: Estimate Std.Err z-value P(>|z|) ab 0.241 0.129 1.876 0.061 total 0.496 0.288 1.718 0.086
Hayes, A. F. (2018) Introduction to Mediation, Moderation, and Conditional Process Analysis (2nd Edition), Guilford Press, London.↩︎