Mediated moderation model with control variables

1,583 views
Skip to first unread message

Wookje Sung

unread,
Jul 12, 2015, 10:59:44 PM7/12/15
to lav...@googlegroups.com
Greetings,

I am trying to run some mediated moderation models (3-way interaction), but I am not so sure if I am doing it correctly.
Would you please confirm my model? I couldn't find answers to this question anywhere else and I am pretty new to R and lavaan.

Here, moderators interact with the IV to predict the mediator (i.e. moderators moderates the relationship between the IV and the mediator).
A sample syntax is as below (IV: independent var., DV: dependent var., Me: mediator, Mo: moderator, and CV: control var.):

Model1 <- '
# direct effect
 DV ~ c1*IV + c2*Me + c3*Mo1 + c4*Mo2 + c5*CV1 + c6*CV2
# mediator
 Me ~ a1*IV + a2*Mo1 + a3*Mo2 + a4*CV1 + a5*CV2
 Dv ~ b*Me
# indirect effect (a*b)
 ab := (a1 + a2 + a3 + a4 + a5)*b
# total effect
 total := c1 + c2 + c3 + c4 + c5 + c6 + (ab)
# 3-way interaction
  interac1 := a1*a2
  interac2 := a1*a3
  interac3 := a2*a3
  interac4:= a1*a2*a3
'

Thank you in advance!


Terrence Jorgensen

unread,
Jul 15, 2015, 12:27:29 PM7/15/15
to lav...@googlegroups.com
Here, moderators interact with the IV to predict the mediator (i.e. moderators moderates the relationship between the IV and the mediator).

Isn't this actually moderated mediation, not mediated moderation?

A sample syntax is as below (IV: independent var., DV: dependent var., Me: mediator, Mo: moderator, and CV: control var.):

Model1 <- '
# direct effect
 DV ~ c1*IV + c2*Me + c3*Mo1 + c4*Mo2 + c5*CV1 + c6*CV2
# mediator
 Me ~ a1*IV + a2*Mo1 + a3*Mo2 + a4*CV1 + a5*CV2
 Dv ~ b*Me

This last line is superflous.  You already labeled the "b" parameter "c2" on the first DV~ line.

Also, you have not specified any moderation, because there are no interaction terms.  Your moderators need to interact with the IV for there to be moderation (i.e., statistical interaction).  You can create product terms in your data.frame, then include those product terms as predictors as well.

Or, if your moderator is categorical, you could test mediated moderation more simply (in my opinion) using equality constraints in a multiple-group model.  
 
# indirect effect (a*b)
 ab := (a1 + a2 + a3 + a4 + a5)*b
# total effect
 total := c1 + c2 + c3 + c4 + c5 + c6 + (ab)
# 3-way interaction
  interac1 := a1*a2
  interac2 := a1*a3
  interac3 := a2*a3
  interac4:= a1*a2*a3
'

Judging from these "interac1-4" parameters, you are confusing products of variables (moderation / interaction) with products of parameters (indirect paths).

Terry

Wookje Sung

unread,
Jul 15, 2015, 10:04:17 PM7/15/15
to lav...@googlegroups.com
Thank you very much, Terry.

I revised my syntax as below:

Model1 <- '
# direct effect
 DV ~ c1*IV + c2*Mo1 + c3*Mo2 + c4*CV1 + c5*CV2 + c6*IVMo1 + c7 *IVMo2 + c8*Mo1Mo2      ## I created IVMo1, IVMo2, and Mo1Mo2 as interaction terms
# mediator
 Me ~ a1*IV + a2*Mo1 + a3*Mo2 + a4*CV1 + a5*CV2 + a6*IVMo1 + a7 *IVMo2 + a8*Mo1Mo2
 Dv ~ b*Me

# indirect effect (a*b)
 ab := a1*b
# total effect
 total := c1 + (ab)

Terrence Jorgensen

unread,
Jul 16, 2015, 6:41:20 AM7/16/15
to lav...@googlegroups.com
Model1 <- '
# direct effect
 DV ~ c1*IV + c2*Mo1 + c3*Mo2 + c4*CV1 + c5*CV2 + c6*IVMo1 + c7 *IVMo2 + c8*Mo1Mo2      ## I created IVMo1, IVMo2, and Mo1Mo2 as interaction terms
# mediator
 Me ~ a1*IV + a2*Mo1 + a3*Mo2 + a4*CV1 + a5*CV2 + a6*IVMo1 + a7 *IVMo2 + a8*Mo1Mo2
 Dv ~ b*Me

# indirect effect (a*b)
 ab := a1*b
# total effect
 total := c1 + (ab)

That's the basic idea, at least for a simple mediation model.  But you have many interactions, so the "total" effect you calculate here is really just the total effect of IV on DV when Mo1 and Mo2 both == 0.  I believe calculating the indirect effects a6*c6 and a7*c7 will provide tests of whether the mediating effect is moderated by Mo1 or by Mo2.  But this is outside my area of expertise.  If you have questions about how to specify your model, you might get more responses on SEMNET, which is a larger forum more dedicated to general topics than just programming in lavaan.  Of course, once you know how you need to specify your model, this is a perfectly good place to check whether you are implementing it correctly in the lavaan model syntax.

Terry

kleines Peh

unread,
Nov 18, 2017, 9:00:57 AM11/18/17
to lavaan
Hi Terry

I tried to follow your advice on how to handle a categorical moderator. Is it correct that I didn't include an interaction then?
(My variables: X is 0 or 1, Mediator(M) is continous, Moderator (Mod) is 0/1 and my outcome variable Y is 0/1)

model<-'# direct effect
Y ~ c(c1,c2)*X + c(b1,b2)*M
# mediator
M ~ c(a1,a2)*X
Y ~ c(b1,b2)*M
#indirect effect
ab1 := a1*b1
ab2 := a2*b2
#total effect
tot1 := c1 + (a1*b1)
tot2 := c2 + (a2*b2)'

fit <- sem(model, data = data, group = "Mod", test = "bootstrap")

If I would want to include controls, do they also need moderator-specific parameters for them? 
One further question regarding my outcome variable - Do I need to consider something if I would want to use a categorical variable with 4 levels? 

Thank you so much for your reply
Best
Petra

Terrence Jorgensen

unread,
Nov 19, 2017, 4:06:15 AM11/19/17
to lavaan
Is it correct that I didn't include an interaction then?

It is not correct or incorrect, but I do think it is somewhat more intuitive to test whether meditating/indirect effects are moderated by a grouping variable using a multigroup model instead of a single-group model with product terms.

my outcome variable Y is 0/1)

Be aware that this is a probit regression when you are interpreting effects on Y.  Regardless of the correct interpretation, it does not affect the way you can compare effects across groups to test for moderation (of direct or indirect effects).

model<-'# direct effect
Y ~ c(c1,c2)*X + c(b1,b2)*M
# mediator
M ~ c(a1,a2)*X
Y ~ c(b1,b2)*M

You included the effect of M on Y twice (the top and bottom lines above).  You should delete one of them to avoid confusion or later mistakes. Usually lavaan gives a warning about duplicate entries.

#indirect effect
ab1 := a1*b1
ab2 := a2*b2
#total effect
tot1 := c1 + (a1*b1)
tot2 := c2 + (a2*b2)'

Correct calculation of effects in both groups.  But in order to test moderation, you need to calculate differences between groups.

ab_diff := ab1 - ab2

The test of that difference is the test of moderated mediation (i.e., whether the indirect effect is moderated by Mod).

fit <- sem(model, data = data, group = "Mod", test = "bootstrap")

You are only requesting a Bollen-Stine bootstrap for the model-fit test statistic, but not bootstrap SEs  (that would require the argument se = "boot").  But I'm not saying either are necessary.  If you have a large enough sample size for bootstrapping to work (i.e., that sampling error is minimal, so a random sample is a good representation of the population), then your sample size is also large enough not to need bootstrap SEs to test your indirect effects.  That is, at large N the indirect effects will have approximately normal sampling distributions, so the delta method lavaan uses to derive SEs would already yield approximately nominal Type I error rates. 

If I would want to include controls, do they also need moderator-specific parameters for them? 

If you include covariate effects, then different slopes across groups implies that the covariate interacts with Mod.  In that case, the effect of X on M (which is a mean difference in M) is not comparable across groups (levels of Mod).  You can first test whether the slope(s) of the covariate(s) are equal across groups by giving them the same labels across groups to constrain them to equality, then comparing the fit of the models with and without equality constraints.  If you cannot reject the null hypothesis of equal covariate effects across groups, then you can compare the effect of X across groups in a subsequent test.  

This is the "homogeneity of slopes assumption" for comparing "adjusted means" in ANCOVA, so you can search Google about that for a more detailed explanation.

Do I need to consider something if I would want to use a categorical variable with 4 levels? 

You would need to have a vector of 4 labels for parameters across 4 groups

Y ~ c(c1,c2,c3,c4)*X + c(b1,b2,b3,b4)*M

With only 2 groups, there is only 1 pairwise comparison, but with 4 groups, there are 6 pairwise comparisons.  So you should first test an omnibus null hypothesis of equality of the indirect effect across all groups, by constraining all component direct paths to equality

a1 == a2
a2
== a3
a3
== a4
b1
== b2
b2
== b3
b3
== b4

Then define your 6 difference parameters in the syntax of the less constrained model only if the omnibus null is rejected.

ab_12 := ab1 - ab2
ab_13 := ab1 - ab3
ab_14 := ab1 - ab4
ab_23 := ab2 - ab3
ab_24 := ab2 - ab4
ab_34 := ab3 - ab4

Terrence D. Jorgensen
Postdoctoral Researcher, Methods and Statistics
Research Institute for Child Development and Education, the University of Amsterdam

kleines Peh

unread,
Nov 19, 2017, 6:14:01 AM11/19/17
to lavaan
Thanks so much - this has been extremely helpful!!!
Just one clarification - your comment 
You would need to have a vector of 4 labels for parameters across 4 groups
refers to a moderator with 4 levels, right? I was referring to a outcome variable (Y) with 4 categories. 
I was wondering if i need to specify that I want to do an ordered logit or if it is enough to make sure Y is an ordered factor. 
Sorry for the misunderstanding.

Terrence Jorgensen

unread,
Nov 20, 2017, 5:04:23 AM11/20/17
to lavaan
ust one clarification - your comment 
You would need to have a vector of 4 labels for parameters across 4 groups
refers to a moderator with 4 levels, right?

Yes

I was referring to a outcome variable (Y) with 4 categories. 
I was wondering if i need to specify that I want to do an ordered logit or if it is enough to make sure Y is an ordered factor. 

Oh, OK.  Yes, you can either declare it an ordered factor in your data.frame, or you can tell sem() that it is ordered:


It will be a probit, not logit model.  You might find the end of this presentation very helpful, since you have categorical mediator and ordinal outcome.

kleines Peh

unread,
Nov 22, 2017, 7:38:14 AM11/22/17
to lav...@googlegroups.com
Thanks a lot. As I want to look at Hayes model 7 however, I think I need to add the interaction (not use grouping variable but a single-group model with product terms).
I came up with the following, but (1) I am not sure if its correct and (2) how to calculate the indirect effects conditional on the (dichotomous) Moderator, as I am not interested in the SDabove and below, but only the effect at "0" and "1" of the Moderator. I am sure the naive approach to just pluck the values in is not correct - but i couldn't find any other solution.
(my variables: independent variable = X, Moderator=W, dependent variable=Y are all coded 0/1 - Mediator = M is continous) 

Thanks!

#create interaction between X and W first in dataframe
data$I_XW <- with(data, X*W)

hayes7 <- ' # regressions
M ~ a1*X
Y ~ b1*M
M ~ a2*W
M ~ a3*I_XW
Y ~ cdash*X

# indirect effects conditional on moderator (a1 + a3*W)*b1
indirect.SDbelow := a1*b1 + a3*0*b1
indirect.SDabove := a1*b1 + a3*1*b1'

# fit model
fit <- sem(model = hayes7,
              data = data,
              se = "bootstrap",
              bootstrap = 5000)

# fit measures
summary(fit,
        fit.measures = TRUE,
        standardize = TRUE,
        rsquare = TRUE)
boot.fit <- parameterEstimates(fit, boot.ci.type="bca.simple")
boot.fit


--
You received this message because you are subscribed to the Google Groups "lavaan" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lavaan+unsubscribe@googlegroups.com.
To post to this group, send email to lav...@googlegroups.com.
Visit this group at https://groups.google.com/group/lavaan.
For more options, visit https://groups.google.com/d/optout.

kleines Peh

unread,
Nov 23, 2017, 7:20:14 AM11/23/17
to lav...@googlegroups.com
sorry, I found the answer in another post https://groups.google.com/d/msg/lavaan/RW_3TMARGhY/UF9-MBk-GKIJ - i must have overlook it.

Reply all
Reply to author
Forward
0 new messages