Search code examples
mixed-modelsr-lavaan

Random effects lavaan


I am running a sem() model and I am trying to include a random effects.

Dataframe:

test <- data.frame(Person = c("a", "a","a", "b", "b", "b", "c", "c", "c"),
                 TrialVariable = c(1, 5, 3, 2, 7,2, 1,1,1),
                 Trait1 = (c(2,2,2,1,1,1,3,3,3)),
                 Trait2 = (c(12,12,12,10,10,10,8,8,8)),
                 Trait3 = (c(2,2,2,1,1,1,3,3,3)),
                 Trait4 = (c(17,17,17,12,12,12,8,8,8)))

Sem model specification

model <- '

# regressions
TrialVariable ~ Trait4
Latent1 ~ TrialVariable

# latent construct
Latent1 =~ Trait1 + Trait2 + Trait3
'

I am in essence trying to run this model in a way so that the regression "TrialVariable ~ Trait4" has random intercept and slope grouped by "Person". In lmer this might look something like this:

regression1 <- lmer(TrialVariable ~ Trait4 +
            (1 |Person), data = test)

In lavaan I have tried to group by "Person"

mod.est <- sem(
  model = model,
  data = test,
  group = "Person",
  estimator = "ULS"
)

but this outputs the error "Error: lavaan->lav_data_full(): some variables have no variance in group 1 : Trait1 Trait2 Trait3 Trait4".

I have not been able to find a solution to this.


Solution

  • I am in essence trying to run this model in a way so that the regression "TrialVariable ~ Trait4" has random intercept and slope

    For that to work, Trait4 would have to be a Level-1 variable. In your reprex data, it varies only between (not within) Person, so it can only have a (Level-2) fixed effect.

    This is what Preacher et al. (2010, Table 1) referred to as a 2-1-2 design, where only the mediator (TrialVariable) is measured at Level 1. This means that the (in)direct effects of Trait4 on Latent1 only occur at Level 2 (i.e., the only relevant variance in TrialVariable is in its Person means).

    You could fit the model to your Level-2 data. This involves calculating the Level-2 component of TrialVariable (i.e., Person means). You can use aggregate() to save those with nonredundant rows of the other Level-2 variables:

    testL2 <- aggregate(cbind(TrialVariable, Trait1, Trait2, Trait3, Trait4) ~ Person,
                        data = test, FUN = mean)
    mod.est <- sem(
      model = model,
      data = testL2,
      #group = "Person",
      estimator = "ULS"
    )
    

    Note that this example fails with your reprex because some of your variables are perfectly correlated (hard to avoid with only 3 Level-2 observations). You can edit your test data to try it with different values, and maybe 5 observations to avoid the sample covariance matrix being non-positive definite. And make Trait4 a Level-1 variable, if that is what you intended (to have a random slope).