Confirmatory Factor Analysis using brms

Hi all,

Not a problem, more a little bit of helpful code. brms can already estimate latent variables using the mi() function for missing data. It can also constrain parameters to be constant. This, I think, provides all the means to fit rudimentary confirmatory factor analysis models.

Simulation code below.


library(tidyverse)
library(brms)

N <- 200

dta <- 
  tibble(
    x = rnorm(N, 0, 1),
    y1 = rnorm(N, 2*x, 1),
    y2 = rnorm(N, 1*x, 1),
    y3 = rnorm(N, 0.5*x, 1),
    xo = as.numeric(NA)
  )

m1 <- 
  brm(
    formula =
      bf(y1 ~ 0 + mi(xo)) +
      bf(y2 ~ 0 + mi(xo)) +
      bf(y3 ~ 0 + mi(xo)) +
      bf(xo | mi() ~ 1) + 
      set_rescor(rescor = FALSE),
    family = gaussian(),
    prior =
      prior(constant(1), class = "b", resp = "y1") +
      prior(constant(1), class = "sigma", resp = "y1") +
      prior(normal(0, 10), class = "b", resp = "y2") +
      prior(constant(1), class = "sigma", resp = "y2") +
      prior(normal(0, 10), class = "b", resp = "y3") +
      prior(constant(1), class = "sigma", resp = "y3") +
      prior(normal(0, 10), class = "Intercept", resp = "xo") +
      prior(cauchy(0, 1), class = "sigma", resp = "xo"),
    data = dta,
    backend = "cmdstanr",
    cores = 4,
    chains = 4,
    threads = threading(2),
    refresh = 5
  )

m1
18 Likes

really useful, thanks so much!

1 Like

Also, the R package blavaan runs Bayesian SEM models, with Stan as the underlying enine. And as it follows the lavaan syntax and familiarity. It includes a bunch useful/common feautures in SEM

This is super helpful, thanks for sharing. Any inkling as to how one might rejig this setup to include correlated factors?

Can you include them as outcomes in a multivariate model and use set_rescor(TRUE)?

Hmm seems like that estimates correlations between all variables, but I’d like the manifest variables to still have 0 correlation. This is actually documented on github issue 957, looks like I’ll need to wait until brms 3.0.

Ah yes, of course. Could you maybe fix some of the correlations to zero by using priors? I can’t remember if you can set priors on individual correlations, but if you can, then you could use constant(0) (Prior Definitions for brms Models — set_prior • brms).

1 Like