如何用R的rethinking包结合Stan拟合带分组的贝叶斯广义可加模型
问题1:为何rethinking的Stan GAM运行失败而brms的可以?
brms封装了贝叶斯GAM的底层实现细节:它会自动处理样条参数化、分类变量的编码转换、Stan代码的生成与维度校验,无需用户手动干预这些环节,因此能规避类型不匹配问题。rethinking的ulam依赖用户手动定义模型的Stan逻辑,对数据类型、参数维度的匹配要求更严格:- 若样条矩阵的维度与参数声明不匹配(比如样条矩阵列数和
b_spline参数长度不一致),会触发类型错误; - 分类变量未转为整数索引直接传入、分组因子的编码格式不符合Stan要求,也会导致校验失败;
quap基于近似推断,对类型和维度的校验宽松,因此能正常运行,但ulam调用Stan进行MCMC时,这些细节问题会被严格拦截。
- 若样条矩阵的维度与参数声明不匹配(比如样条矩阵列数和
问题2:在rethinking中纳入分组因子group的可行示例
步骤1:模拟测试数据
library(rethinking) library(mgcv) set.seed(123) # 生成基础变量 n <- 500 x <- rnorm(n) cat_var <- sample(c("A", "B", "C"), n, replace = TRUE) group_var <- sample(paste0("Group_", 1:10), n, replace = TRUE) # 构造三次样条矩阵(遵循Pedersen等人的方法) spline_x <- s(x, k = 10, bs = "cr") X_spline <- predict(spline_x, newdata = data.frame(x = x), type = "lpmatrix") # 生成带分组效应的响应变量 beta_cat <- c(0, 0.8, -0.5) # 以"A"为基准类别 sigma_group <- 0.3 alpha_group <- rnorm(length(unique(group_var)), 0, sigma_group) mu <- X_spline %*% rnorm(ncol(X_spline), 0, 0.5) + beta_cat[as.integer(cat_var)] + alpha_group[match(group_var, unique(group_var))] y <- rnorm(n, mu, 0.2) # 整理数据,预处理变量 dat <- data.frame(y, x, cat_var, group_var, X_spline) dat$cat_idx <- as.integer(dat$cat_var) dat$group_idx <- as.integer(as.factor(dat$group_var)) n_group <- max(dat$group_idx) n_cat <- max(dat$cat_idx) n_spline <- ncol(dat$X_spline)
步骤2:用ulam构建含分组因子的贝叶斯GAM
model_gam_group <- ulam( alist( y ~ normal(mu, sigma), # 线性预测器:全局截距 + 样条效应 + 分类效应 + 分组随机截距 mu <- a + X_spline %*% b_spline + b_cat[cat_idx] + z_group[group_idx], # 样条参数先验(模拟mgcv的平滑惩罚) b_spline ~ normal(0, 0.5), # 分类变量先验:固定基准类别参数为0,避免共线性 b_cat[1] <- 0, b_cat[2:n_cat] ~ normal(0, 0.5), # 分组随机截距先验 z_group ~ normal(0, sigma_group), sigma_group ~ exponential(1), # 全局参数先验 a ~ normal(0, 1), sigma ~ exponential(1) ), data = dat, chains = 4, cores = 4, iter = 2000 ) # 查看模型结果 precis(model_gam_group, depth = 2)
核心细节说明
- 样条矩阵
X_spline直接传入模型,参数b_spline的维度与矩阵列数自动匹配; - 分类变量转为整数索引
cat_idx,并固定基准类别参数为0,解决共线性问题; - 分组因子转为整数索引
group_idx,通过z_group定义随机截距,sigma_group控制组间变异程度; - 样条参数的先验选择
normal(0, 0.5),模拟mgcv中的平滑惩罚逻辑,也可替换为student_t等稳健先验。
内容的提问来源于stack exchange,提问作者Luka Seamus Wright
相关产品推荐
相关产品推荐

