Brms cumulative model with varying response categories

I am relatively new to IRT and brms, so please forgive any errors or misunderstandings in my model.

I am trying to fit a multidimensional model in brms using the cumulative family with a logit link. My data come from the German Socioeconomic Panel (SOEP), and I have selected 14 items for the model.

The challenge is that the SOEP questions have varying numbers of response categories (ranging from 3 to 7 in the items I am using). It appears that brms requires a consistent scale across all items, but I prefer not to reduce, for example, a 7-category Likert scale to 3 categories.

Is there a way to accommodate varying response scales among items in brms? Based on conversations here and here, it looks like it is possible in Stan, but I have not had any success in brms.

For reference, the code below demonstrates what I would like to do using 9 generated items with 3 different scales (3-category, 5, and 7) distributed among 3 dimensions. I am using brms version 2.20.4 on Windows.

####################### sample data
id <- 500 

# creating a data frame with respondents, items, and dimensions
d <- data.frame(
  id = rep(1:id, each = 9),
  item = rep(1:9, id),
  dim = rep(rep(1:3, each = 3), id)
)

# generating integer y values based on item
y <- function(item) {
  switch(as.character(item),
         "1" = sample(1:3, 1), 
         "2" = sample(1:5, 1),
         "3" = sample(1:7, 1),
         "4" = sample(1:3, 1), 
         "5" = sample(1:5, 1),
         "6" = sample(1:7, 1),
         "7" = sample(1:3, 1), 
         "8" = sample(1:5, 1),
         "9" = sample(1:7, 1)
  )
}

d$y <- sapply(d$item, y) 

head(d, 20) 
length(unique(d$id)) 
nrow(d) 

#########################################

formula <- bf(
  y ~ 1 + (1 |i| item) + (0 + dim | id), disc ~ 1 + (1 |i| item))

prior <- 
  prior("lkj(1)", class = "cor") +
  prior("student_t(3, 0, 2.5)", class = "Intercept") +
  prior("student_t(3, 0, 2.5)", class = "sd") +
  prior("normal(0, 1)", class = "Intercept", dpar = "disc") 

fit1 <- brm(
  formula = formula,
  data = d,
  family = brmsfamily("cumulative", "logit", threshold = "flexible"),
  prior = prior,
  chains = 4,  
  iter = 2000,  
  warmup = 1000,
  thin = 2, 
  control = list(adapt_delta = 0.99),
  cores = parallel::detectCores()
)

You may want to take a look at the thres() addition term that you can add via

y | thres(…) ~ …

You can check out the corresponding docs via ?resp_thres.

2 Likes

Thank you, Paul!