You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在rjags中实现三层嵌套线性混合效应模型?

在rjags中实现三层嵌套线性混合效应模型

你遇到的问题核心是混淆了嵌套模型和交叉模型的参数化方式,导致你的JAGS代码尝试估计不可识别的参数,最终出现个体随机效应被过度惩罚的情况。让我们一步步理清并修正这个问题:

问题根源:嵌套模型 vs 交叉模型

你提到的lme4代码lmer(yN ~ x + (1 |group/indiv), data=qq)等价于lmer(yN ~ x + (1|group) + (1|group:indiv), data=qq),这是真正的嵌套模型:个体的随机效应是嵌套在组内的,即每个个体的截距是围绕其所属组的截距波动的。

而你写的JAGS代码对应的是lmer(yN ~ x + (1|group) + (1|indiv), data=qq),这是交叉模型——当每个个体只属于一个组时,这个模型是不可识别的:个体的随机效应已经包含了组的效应,导致模型无法区分组和个体的独立贡献,最终出现参数被过度压缩(惩罚)的情况。

正确的JAGS嵌套模型代码

我们可以直接实现嵌套结构,不需要创建额外的交互变量,核心是让个体的随机效应以其所属组的随机效应为均值,而不是直接围绕总体均值波动。

完整JAGS模型代码

st <- "
model {
  # 固定效应
  beta0 ~ dnorm(0, 0.0001)  # 总体截距
  beta1 ~ dnorm(0, 0.0001)  # x的斜率
  
  # 残差精度
  tau_resid ~ dgamma(0.01, 0.01)
  sigma_resid <- sqrt(1/tau_resid)
  
  # 组水平随机效应:每个组的截距围绕总体均值波动
  for (k in 1:nGrp) {
    b_group[k] ~ dnorm(0, tau_group)
  }
  tau_group ~ dgamma(0.001, 0.001)
  sigma_group <- sqrt(1/tau_group)
  
  # 个体水平随机效应:每个个体的截距围绕其所属组的截距波动
  for (j in 1:nInd) {
    b_indiv[j] ~ dnorm(b_group[grp_of_ind[j]], tau_indiv)
  }
  tau_indiv ~ dgamma(0.001, 0.001)
  sigma_indiv <- sqrt(1/tau_indiv)
  
  # 观测模型
  for (i in 1:n) {
    mu[i] <- beta0 + beta1 * x[i] + b_indiv[ind[i]]
    y[i] ~ dnorm(mu[i], tau_resid)
  }
}
"

关键修改点

  1. 嵌套结构的参数化:个体随机效应b_indiv[j]的先验均值不再是0,而是其所属组的随机效应b_group[grp_of_ind[j]],完美对应(1|group/indiv)的嵌套逻辑。
  2. 新增映射关系:我们需要一个向量grp_of_ind,用来存储每个个体对应的组索引(比如个体a属于组1,个体b属于组1,等等)。

运行模型的准备代码

在运行JAGS之前,先创建grp_of_ind向量:

library(rjags)
library(lme4)

# 处理数据集,创建个体到组的映射
qq$ind_num <- as.integer(qq$indiv)
qq$group_num <- as.integer(qq$group)
# 得到每个个体对应的组:取每个个体的第一个观测的组编号
grp_of_ind <- tapply(qq$group_num, qq$ind_num, function(x) unique(x))
grp_of_ind <- unname(grp_of_ind)

# 整理JAGS输入数据
jags_data <- list(
  y = qq$yN,
  x = qq$x,
  ind = qq$ind_num,
  n = nrow(qq),
  nInd = length(unique(qq$ind_num)),
  nGrp = length(unique(qq$group_num)),
  grp_of_ind = grp_of_ind
)

# 初始化并运行模型
mod <- jags.model(
  textConnection(st),
  data = jags_data,
  n.adapt = 100000,  # 不需要1e6这么大,1e5足够
  inits = list(.RNG.seed=1, .RNG.name="base::Wichmann-Hill")
)
update(mod, n.iter=50000)  # 额外的 burn-in
mod_samples <- coda.samples(
  mod,
  variable.names=c("beta0", "beta1", "sigma_group", "sigma_indiv", "sigma_resid"),
  n.iter=500000,
  thin=10
)

# 查看结果
summary(mod_samples)

对应Pastes数据集的实现

对于Pastes数据集的嵌套模型lmer(strength ~ 1 + (1|batch/cask), data=Pastes),我们可以用完全相同的逻辑实现,不需要创建batch:cask交互变量:

JAGS模型代码

pastes_st <- "
model {
  # 总体截距
  beta0 ~ dnorm(0, 0.0001)
  
  # 残差精度
  tau_resid ~ dgamma(0.01, 0.01)
  sigma_resid <- sqrt(1/tau_resid)
  
  # 批次(batch)水平随机效应
  for (b in 1:nBatch) {
    b_batch[b] ~ dnorm(0, tau_batch)
  }
  tau_batch ~ dgamma(0.001, 0.001)
  sigma_batch <- sqrt(1/tau_batch)
  
  # 桶(cask)水平随机效应:嵌套在批次中
  for (c in 1:nCask) {
    b_cask[c] ~ dnorm(b_batch[batch_of_cask[c]], tau_cask)
  }
  tau_cask ~ dgamma(0.001, 0.001)
  sigma_cask <- sqrt(1/tau_cask)
  
  # 观测模型
  for (i in 1:n) {
    mu[i] <- beta0 + b_cask[cask[i]]
    strength[i] ~ dnorm(mu[i], tau_resid)
  }
}
"

运行代码

data(Pastes, package="lme4")
Pastes$batch_num <- as.integer(Pastes$batch)
Pastes$cask_num <- as.integer(Pastes$cask)
# 创建桶到批次的映射
batch_of_cask <- tapply(Pastes$batch_num, Pastes$cask_num, function(x) unique(x))
batch_of_cask <- unname(batch_of_cask)

pastes_data <- list(
  strength = Pastes$strength,
  cask = Pastes$cask_num,
  n = nrow(Pastes),
  nBatch = length(unique(Pastes$batch_num)),
  nCask = length(unique(Pastes$cask_num)),
  batch_of_cask = batch_of_cask
)

pastes_mod <- jags.model(
  textConnection(pastes_st),
  data = pastes_data,
  n.adapt = 10000,
  inits = list(.RNG.seed=2)
)
update(pastes_mod, n.iter=5000)
pastes_samples <- coda.samples(
  pastes_mod,
  variable.names=c("beta0", "sigma_batch", "sigma_cask", "sigma_resid"),
  n.iter=100000,
  thin=5
)
summary(pastes_samples)

为什么你的原代码会出现惩罚过度?

你的原代码同时估计组和个体相对于总体均值的随机效应,当个体完全嵌套在组内时,这两个效应是共线性的——模型无法区分“组带来的差异”和“个体带来的差异”,因此JAGS会自动压缩其中一个效应的方差(通常是个体效应,因为组的水平更少),最终出现你看到的“个体水平随机效应惩罚过度”的情况。

通过改用嵌套参数化(个体效应围绕组效应波动),我们让模型的参数变得可识别,就能得到和lme4一致的合理估计结果。

内容的提问来源于stack exchange,提问作者user2957945

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:45:06