0

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

user438383
  • 5,716
  • 8
  • 28
  • 43
socialscientist
  • 3,759
  • 5
  • 23
  • 58
  • 2
    afaik, you can only specify a mixed-effects model that is equivalent to a CFA (with parallel-indicator constraints). Regressing a common factor on another common factor is analogous to regressing random effects on each other, which is not a feature of any standard mixed-effects modeling packages I am aware of (unless the superbeast MLwiN can do something like this?). You could certainly do so in a Bayesian hierarchical model, using flexible software like Stan or JAGS. – Terrence Jun 10 '22 at 13:57
  • @Terrence Yes, I was using `lme4` to see if anyone had any ideas that would let me use `brms`. Maybe this could be done in `brms` with the non-linear capabilities https://cran.r-project.org/web/packages/brms/vignettes/brms_nonlinear.html but I'm not sure what actual model is specified with those arguments. I'll probably adapt what is done in this code in rstan https://discourse.mc-stan.org/t/multi-group-confirmatory-factor-analysis-how-to-handle-the-cholesky-factor-correlations/12687/2 to (a) specify a regression coefficient not a correlation (i.e. add a mean) and (b) include a predictor. – socialscientist Jun 11 '22 at 01:36

0 Answers0