I’m trying to set individual boundaries for each coefficient in the prior when fitting a linear model in brms.
Here’s the code to simulate a dataset with 3 groups, where each group comes from a truncated normal distribution where the truncation boundary, the mean, and the standard deviation differ per group.
library(truncnorm)
library(dplyr)
library(brms)
library(ggplot2)
LODs = c(2, 3, 4)
n_per_grp <- 50
groups <- paste0("0", 1:3)
N <- n_per_grp * length(groups)
# Example group‑specific means and SDs for the truncated normal
mu <- 2:4
sigma <- c(0.5, 1, 2)
set.seed(2024)
dat_sim <- lapply(seq_along(groups), function(i) {
out = data.frame(
group = groups[i],
y0 = rnorm(n = n_per_grp, mean = mu[i], sd = sigma[i])
) %>%
mutate(censored = ifelse(y0 < LODs[i], "left", "none"),
y = ifelse(y0 < LODs[i], LODs[i], y0))
return(out)
}) %>%
bind_rows()
dat_sim %>%
ggplot(aes(x = group, y = y)) +
geom_jitter(height = 0, width = 0.1) +
theme_bw()
I’m trying to fit the following model
mod_formula = bf(
y ~ 0 + group,
sigma ~ 0 + group
)
prior_mod_1 = c(
prior(normal(2, 2), class = "b", coef = "group01", lb = 1),
prior(normal(3, 2), class = "b", coef = "group02", lb = 2),
prior(normal(4, 2), class = "b", coef = "group03", lb = 3),
prior(normal(0, 3), dpar = "sigma")
)
mod_1 = brm(
formula = mod_formula,
data = dat_sim,
prior = prior_mod_1,
iter = 5000,
warmup = 3000,
chains = 6,
cores = 6,
seed = 2024,
backend = "cmdstanr"
)
But I get the following error:
Error: Prior argument 'coef' may not be specified when using boundaries.
I know that the fact that we cannot specify a specific boundary per group is well known within the brms team. It is mentioned (at least) here, here and here.
In some of those forums, it is mentioned that the non-linear syntax can be used to circumvent this restriction. However, I think that only works if I have two different boundaries. Is there a way to use the non-linear syntax to set the boundaries in the prior using the example I show with 3 groups? If it is not through the non-linear syntax, is there another way to do it?
Thanks!
R version 4.4.3 (2025-02-28 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 22631)
Matrix products: default
locale:
[1] LC_COLLATE=English_United States.utf8 LC_CTYPE=English_United States.utf8 LC_MONETARY=English_United States.utf8
[4] LC_NUMERIC=C LC_TIME=English_United States.utf8
time zone: Europe/Berlin
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] rstan_2.32.7 StanHeaders_2.32.10 brms_2.22.0 Rcpp_1.0.14 ggplot2_3.5.2
[6] dplyr_1.1.4 truncnorm_1.0-9
loaded via a namespace (and not attached):
[1] gtable_0.3.6 tensorA_0.36.2.1 QuickJSR_1.7.0 xfun_0.51 processx_3.8.6
[6] inline_0.3.21 lattice_0.22-6 vctrs_0.6.5 tools_4.4.3 ps_1.9.1
[11] generics_0.1.3 stats4_4.4.3 parallel_4.4.3 sandwich_3.1-1 tibble_3.2.1
[16] cmdstanr_0.9.0 pkgconfig_2.0.3 Matrix_1.7-2 data.table_1.17.0 checkmate_2.3.2
[21] RColorBrewer_1.1-3 distributional_0.5.0 RcppParallel_5.1.10 lifecycle_1.0.4 compiler_4.4.3
[26] farver_2.1.2 stringr_1.5.1 Brobdingnag_1.2-9 codetools_0.2-20 htmltools_0.5.8.1
[31] bayesplot_1.11.1 yaml_2.3.10 pillar_1.10.2 MASS_7.3-64 bridgesampling_1.1-2
[36] abind_1.4-8 multcomp_1.4-28 nlme_3.1-167 posterior_1.6.1 tidyselect_1.2.1
[41] digest_0.6.37 mvtnorm_1.3-3 stringi_1.8.4 reshape2_1.4.4 labeling_0.4.3
[46] splines_4.4.3 fastmap_1.2.0 grid_4.4.3 cli_3.6.4 magrittr_2.0.3
[51] loo_2.8.0.9000 pkgbuild_1.4.7 survival_3.8-3 TH.data_1.1-3 withr_3.0.2
[56] scales_1.4.0 backports_1.5.0 estimability_1.5.1 rmarkdown_2.29 matrixStats_1.5.0
[61] emmeans_1.11.0 gridExtra_2.3 zoo_1.8-14 coda_0.19-4.1 evaluate_1.0.3
[66] knitr_1.50 rstantools_2.4.0 rlang_1.1.5 xtable_1.8-4 glue_1.8.0
[71] pkgload_1.4.0 rstudioapi_0.17.1 jsonlite_1.9.1 plyr_1.8.9 R6_2.6.1