tci
tci

Reputation: 81

Plot interaction effect in sem model with observed variables in R

I am estimating an SEM model that has observed variables. I am using SEM to handle missing data using FIML. My model has an interaction term to test for moderation. Here is a toy example that illustrates the issue.

library(lavaan)
library(car)
library(dplyr)

data(starwars)

sw2 <- starwars %>% mutate(
  male = Recode(sex, "'male' = 1; NA=NA; else = 0"),
  human = Recode(species, "'Human' = 1; NA=NA; else = 0"),
  maleXby = male * birth_year,
)

mod <- 'mass ~ height + human + male + birth_year + maleXby'
fit <- sem(mod, data = sw2, missing="fiml.x")
summary(fit)

What I want to do is plot the interaction term like a margin plot, to visualize the interaction effect. But package like library(interactions) does not work with an object of class lavaan. How could I visualize this? Is there a package (like interactions) that makes this easier.

Upvotes: 1

Views: 1168

Answers (1)

Terrence
Terrence

Reputation: 1260

You could fit this model using lm(), but I think you want to be able to use FIML estimates, yes? In that case, you could use the emmeans package, which can work on lavaan-class objects if you have the semTools package loaded.

You didn't say which predictor was focal vs. moderator, but I assume you want to treat male as moderator because it is a grouping variable. The example below can be adapted by switching their roles in the pairs() function, as well as by selecting different birth_year levels at= which to probe the effect of male. When birth_year is the focal predictor, its linear effect will be the same regardless of which levels are chosen, so I chose the full range() below.

library(emmeans)
library(semTools)

## for ease of use, fit model using colon operator
mod <- 'mass ~ height + human + male + birth_year + male:birth_year'
fit <- sem(mod, data = sw2, missing = "fiml.x")

## calculate expected marginal means for multiple 
## levels of male (1:0) and birth_year
BYrange <- range(sw2$birth_year, na.rm = TRUE)
em.mass <- emmeans(fit, specs = ~ birth_year | male, 
                   at = list(male = 1:0, birth_year = BYrange),
                   # because SEMs can have multiple DVs:
                   lavaan.DV = "mass")
em.mass
## probe effect of year across sex
rbind(pairs(em.mass))
## plot effect of year across sex
emmip(em.mass, male ~ birth_year)   # 2 lines in same plot
emmip(em.mass, ~ birth_year | male) # in separate panels

Upvotes: 2

Related Questions