Background
I am trying to convert a lavaan
structural equation model into an lmer
multi-level item response model. The model has 2 latent factors measured by 3 variables apiece. One of the latent factors is regressed on the other latent factor and a group-level, time-invariant, exogenous covariate ("sex").
Issue
Can someone advise on how to build in the regressions between the latent variables in the SEM into the multilevel model? In the minimal working example below, I fit the lavaan
model and try to implement a hierarchical version of it in lmer
but cannot figure out how to add the latent regression.
Working Example
Prepare data for lme4
and lavaan
library(dplyr)
library(tidyr)
library(lavaan)
library(lme4)
library(semPlot)
# Load, keep variables in model, drop NAs and normalize all latent variable
# indicators then let all measures of lv2 be continuous and all measures of
# lv1 be ordinal
dat <- lavaan::HolzingerSwineford1939 %>%
select(starts_with("x") | sex) %>%
select(-c("x7","x8","x9")) %>%
mutate(sex = sex - 2) %>%
mutate(across(starts_with("x"), ~ scale(.x))) %>%
mutate(across(c(paste0("x", 1:3)),
~ case_when(. < -0.5 ~ 1,
. >= -0.5 &
. < 0.5 ~ 2,
. >= 0.5 ~ 3))) %>%
na.omit()
# Prepare data for 1 pl multilevel item response model
# Convert to long format: each row is an item response add indicators for the latent factor that item loads onto and a variable with the nominal
# category for that variable
dat_irt <- dat %>% mutate(id = 1:n()) %>%
pivot_longer(names_to = "item",
cols = starts_with("x"),
values_to = "response") %>%
mutate(lv1_item = case_when(item %in% paste0("x",1:3) ~ 1, TRUE ~ 0),
lv2_item = case_when(item %in% paste0("x",4:6) ~ 1, TRUE ~ 0),
item_type = case_when(lv1_item == 1 ~ "lv1", TRUE ~ "lv2"))
lavaan
Model
m1 <- 'lv1 =~ x1 + x2 + x3
lv2 =~ x4 + x5 + x6
lv2 ~ lv1 + sex'
m1_out <- lavaan::sem(model = m1, data = dat)
# Look at path diagram and model output
m1_out %>% semPaths()
lme4
Hierarchical Model
# Fit 1-factor Rasch (1-pl) model
dat_irt %>% lme4::lmer(response ~ -1 + item + (1 | id), .) %>% summary()
# Now "regress" lv1 on lv2...as best as I can tell, this produces an ability
# estimate for each id (person) but I don't see how that's a "regression"
dat_irt %>% lme4::lmer(response ~ -1 + item + (-1 + item_type | id), .) %>% summary()
# Finally add time-invariant, exogenous, binary, id-level "sex" covariate...
# no idea where to add this since I only want it to predict lv2!
dat_irt %>% lme4::lmer(response ~ -1 + item + sex + (-1 + sex + item_type | id), .) %>% summary()