SEM R lavaan:
Latent Interactions (Moderation) With Double Mean Centering

Arndt Regorz, Dipl. Kfm. & M.Sc. Psychology, 11/29/2022


(Note: When you click on this video you are using a service offered by YouTube.)

Here is the R code for the Youtube tutorial about latent interactions in lavaan:

library(lavaan)
library(semTools)

head(mydata)

# Testing model fit (without interaction)

# Measurement model (step 1)

test_model <- '
# loadings
iv =~ IV1 + IV2 + IV3
mod =~ MOD1 + MOD2 + MOD3
dv =~ DV1 + DV2 + DV3
'

test_fit <- cfa(test_model, data = mydata, estimator="MLM")

summary(test_fit, fit.measures = TRUE, standardized=TRUE)

mi <- modificationindices(test_fit)
mi[mi$mi>10,]

# Structural model (step 2; not necessary here because of saturated structural part)

test_model2 <- '
# loadings
iv =~ IV1 + IV2 + IV3
mod =~ MOD1 + MOD2 + MOD3
dv =~ DV1 + DV2 + DV3

# regression
dv ~ iv + mod
'

test_fit2 <- sem(test_model2, data = mydata, estimator="MLM")

summary(test_fit2, fit.measures = TRUE, standardized=TRUE)

mi <- modificationindices(test_fit)
mi[mi$mi>10,]

# Double Mean Centering

mydata_dmc <- indProd (mydata , var1 = c("IV1", "IV2", "IV3"),
var2 = c("MOD1", "MOD2", "MOD3"),
match = FALSE , meanC = TRUE ,
residualC = FALSE , doubleMC = TRUE)

head(mydata_dmc)

# Model estimation with latent interaction

int_model <- '
# Loadings
iv =~ IV1 + IV2 + IV3
mod =~ MOD1 + MOD2 + MOD3
dv =~ DV1 + DV2 + DV3
int =~ IV1.MOD1 + IV1.MOD2 + IV1.MOD3 + IV2.MOD1 + IV2.MOD2 +
IV2.MOD3 + IV3.MOD1 + IV3.MOD2 + IV3.MOD3

# Regression
dv ~ iv + mod + int

# Error covariances
IV1.MOD1 ~~ IV1.MOD2 + IV1.MOD3 + IV2.MOD1 + IV3.MOD1
IV1.MOD2 ~~ IV1.MOD3 + IV2.MOD2 + IV3.MOD2
IV1.MOD3 ~~ IV2.MOD3 + IV3.MOD3
IV2.MOD1 ~~ IV2.MOD2 + IV2.MOD3 + IV3.MOD1
IV2.MOD2 ~~ IV2.MOD3 + IV3.MOD2
IV2.MOD3 ~~ IV3.MOD3
IV3.MOD1 ~~ IV3.MOD2 + IV3.MOD3
IV3.MOD2 ~~ IV3.MOD3
'

int_fit <- sem(int_model, data = mydata_dmc, estimator="MLM")

summary(int_fit, fit.measures = TRUE, standardized=TRUE)

# Simple Slopes

probe <- probe2WayMC(int_fit, c("iv", "mod", "int"), "dv", "mod",
c(-sqrt(1.462),0, sqrt(1.462)))
probe

plotProbe(probe, c(-3,3))

# Double mean centering done manually

# Step 1: 1st mean centering of indicators for IV and MOD

attach(mydata2)
mydata2$IV1c <- scale(IV1, scale = FALSE)
mydata2$IV2c <- scale(IV2, scale = FALSE)
mydata2$IV3c <- scale(IV3, scale = FALSE)
mydata2$MOD1c <- scale(MOD1, scale = FALSE)
mydata2$MOD2c <- scale(MOD2, scale = FALSE)
mydata2$MOD3c <- scale(MOD3, scale = FALSE)
detach(mydata2)

# Step 2: Product terms

attach(mydata2)
mydata2$I1M1 <- IV1c * MOD1c
mydata2$I1M2 <- IV1c * MOD2c
mydata2$I1M3 <- IV1c * MOD3c
mydata2$I2M1 <- IV2c * MOD1c
mydata2$I2M2 <- IV2c * MOD2c
mydata2$I2M3 <- IV2c * MOD3c
mydata2$I3M1 <- IV3c * MOD1c
mydata2$I3M2 <- IV3c * MOD2c
mydata2$I3M3 <- IV3c * MOD3c
detach(mydata2)

# Step 3: 2nd mean centering (product terms)

attach(mydata2)
mydata2$I1M1c <- scale(I1M1, scale = FALSE)
mydata2$I1M2c <- scale(I1M2, scale = FALSE)
mydata2$I1M3c <- scale(I1M3, scale = FALSE)
mydata2$I2M1c <- scale(I2M1, scale = FALSE)
mydata2$I2M2c <- scale(I2M2, scale = FALSE)
mydata2$I2M3c <- scale(I2M3, scale = FALSE)
mydata2$I3M1c <- scale(I3M1, scale = FALSE)
mydata2$I3M2c <- scale(I3M2, scale = FALSE)
mydata2$I3M3c <- scale(I3M3, scale = FALSE)
detach(mydata2)

head(mydata2)