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.

Setting up a simple mediation model

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

Example Dichotomous X

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 psych::mediate().

First, we’ll take a look at our data table called pmi:

# 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,

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 summary()

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.

This figure shows a simple mediation diagram
a simple mediation diagram

Accessing the model object

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.

For example:

The mean of ab


The sd of ab


The bootstrapped CIs of ab

       2.5%       97.5% 
0.003656523 0.523096406 

Downsides of psych

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 PROCESS macro.

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.

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")
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

                   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

                   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

  1. Hayes, A. F. (2018) Introduction to Mediation, Moderation, and Conditional Process Analysis (2nd Edition), Guilford Press, London.↩︎

CC-BY-NC-SA-4.0Lincoln J Colling