brms
underlying Stan
code for a non-nested multi-level model, e.g.,
make_stancode(y ~ 1 + (1 | re_1) + (1 | re_2) + (1 | re_3), data = d)
is identical to the Stan
code for a nested model,
make_stancode(y ~ 1 + (1 | re_1 / re_2 / re_3), data = d)
whether or not the nesting is natural. It looks like the difference between brms
-generated Stan
models are in how they index the random effects. If naturally nested, it seems each random effect assumes the indexing of the level before it. Is that right? And if not-naturally nested, how does brms
approach indexing?
Here’s some code:
# Simulated data
N <- 100
y <- rnorm(N)
# naturally nested random effects
re_1 <- sample(LETTERS[1:5], N, replace = T)
re_2 <- paste0(re_1, sample(seq(5), N, replace = T))
re_3 <- paste0(re_2, sample(seq(5), N, replace = T))
d <- data.frame(y, re_1, re_2, re_3)
# create stan code and data for nonnested and nested models
# using naturally nested random effects
library(brms)
nonnested_code <- make_stancode(y ~ 1 + (1 | re_1) + (1 | re_2) + (1 | re_3), data = d)
nonnested_data <- make_standata(y ~ 1 + (1 | re_1) + (1 | re_2) + (1 | re_3), data = d)
nested_code <- make_stancode(y ~ 1 + (1 | re_1 / re_2 / re_3), data = d)
nested_data <- make_standata(y ~ 1 + (1 | re_1 / re_2 / re_3), data = d)
# test for equality in code and data
identical(nonnested_code, nested_code) # TRUE
identical(nonnested_data, nested_data) # TRUE
# not naturally nested random effects
re_2 <- paste0(sample(seq(5), N, replace = T))
re_3 <- paste0(sample(seq(5), N, replace = T))
d <- data.frame(y, re_1, re_2, re_3)
# create stan code and data for nonnested and nested models
# using naturally nested random effects
nonnested_code <- make_stancode(y ~ 1 + (1 | re_1) + (1 | re_2) + (1 | re_3), data = d)
nonnested_data <- make_standata(y ~ 1 + (1 | re_1) + (1 | re_2) + (1 | re_3), data = d)
nested_code <- make_stancode(y ~ 1 + (1 | re_1 / re_2 / re_3), data = d)
nested_data <- make_standata(y ~ 1 + (1 | re_1 / re_2 / re_3), data = d)
# test for equality in code and data
identical(nonnested_code, nested_code) # TRUE
identical(nonnested_data, nested_data) # FALSE
writeLines(nested_code) # look at Stan code
str(nonnested_data)
str(nested_data)