贝叶斯层次模型采样咨询:PyMC3数学原理及参数估计疑问
我完全懂这种抓心挠肝的感觉——捧着PyMC3的应用书,代码跑起来没问题,但底层采样的数学逻辑全是黑箱,就像只会用手机却不知道芯片怎么工作一样😅。咱们结合你提到的θ₁、θ₂、θ₃和对应样本,一步步把层次模型的采样原理拆明白。
先明确你的层次模型框架
首先得锚定咱们讨论的模型(我先假设是最常见的共享超先验层次模型,如果你是其他结构可以随时调整):
- 超参数:
μ(所有θ的全局均值)、τ(所有θ的全局方差,或者用σ=√τ表示标准差) - 层次参数:
θ₁、θ₂、θ₃,每个θᵢ都从超分布中生成:θᵢ ~ Normal(μ, τ) - 观测数据:
y₁,y₂,y₃ ~ Normal(θ₁, σ_y)(σ_y是观测噪声,假设已知或有自己的先验)x₁~x₅ ~ Normal(θ₂, σ_x)z₁,z₂ ~ Normal(θ₃, σ_z)
这个框架的核心是:数据少的θ₃可以借用θ₁、θ₂的信息(因为它们共享超先验),这也是层次模型的最大优势——收缩估计,避免小样本下的极端估计。
采样的核心逻辑:拆解联合后验为条件后验
层次模型的采样之所以可行,是因为我们可以把复杂的联合后验分布拆成多个简单的条件后验分布——这是Gibbs采样的核心,而PyMC3默认用的NUTS(No-U-Turn Sampler)是更高效的自适应采样器,但底层逻辑还是围绕条件后验展开的。
咱们先手动推导你的例子里的条件后验,帮你吃透数学原理,再联系PyMC3的实现。
1. 单个θᵢ的条件后验(以θ₁为例)
当固定其他所有参数(μ、τ、θ₂、θ₃、σ_y等)时,θ₁的条件后验只和它的先验以及对应的观测数据y₁~y₃有关。
根据贝叶斯公式:
P(θ₁ | 其他所有参数, y₁~y₃) ∝ P(y₁~y₃ | θ₁) × P(θ₁ | μ, τ)
代入正态分布的概率密度函数,化简后会得到一个新的正态分布:θ₁ | ... ~ Normal(μ₁_post, τ₁_post)
其中:
- 后验精度(1/方差):
τ₁_post = 3/σ_y² + 1/τ(3是y样本的数量) - 后验均值:
μ₁_post = ( (y₁+y₂+y₃)/σ_y² + μ/τ ) / τ₁_post
这个逻辑对θ₂、θ₃完全适用,只是样本数量不同:
- θ₂的后验精度是
5/σ_x² + 1/τ(5是x样本数),均值是(x₁+...+x₅)/σ_x² + μ/τ除以精度 - θ₃的后验精度是
2/σ_z² + 1/τ(2是z样本数),均值是(z₁+z₂)/σ_z² + μ/τ除以精度
说白了:样本越多,观测数据对θᵢ的后验影响越大——精度里的样本数项占比越高,θᵢ的后验分布就越集中,估计越确定。
2. 超参数μ的条件后验
当固定θ₁、θ₂、θ₃和τ时,μ的条件后验也是正态分布:
假设μ的先验是Normal(μ₀, τ₀),化简后:μ | ... ~ Normal(μ_post, τ_post)
其中:
- 后验精度:
τ_post = 3/τ + 1/τ₀(3是θ的数量) - 后验均值:
μ_post = ( (θ₁+θ₂+θ₃)/τ + μ₀/τ₀ ) / τ_post
这里的μ是所有θ的“中心”,所以它的后验会被所有θ的当前值拉向它们的平均。
3. 超参数τ的条件后验
τ是θ的方差(控制θ之间的离散程度),通常我们用精度τ=1/σ²来简化计算。如果τ的先验是Gamma(a, b),那么它的条件后验是逆Gamma分布:τ | ... ~ Gamma( a + 3/2, b + (1/2)×[(θ₁-μ)² + (θ₂-μ)² + (θ₃-μ)²] )
这里的3还是θ的数量,τ的后验会根据θ之间的离散程度调整:θ越分散,τ的后验均值越大。
Gibbs采样的迭代流程(手动版)
把这些条件后验串起来,就是层次模型的采样步骤:
- 初始化参数:给
μ、τ、θ₁、θ₂、θ₃一个初始值(比如μ=0,τ=1,θ₁取y的均值,θ₂取x的均值,θ₃取z的均值) - 迭代采样(比如10000次):
- 采样θ₁:从刚才推导的正态条件后验里抽一个新值
- 采样θ₂:同理,从它的正态条件后验抽新值
- 采样θ₃:同理
- 采样μ:从它的正态条件后验抽新值
- 采样τ:从它的逆Gamma条件后验抽新值
- 燃烧期+保留样本:扔掉前2000次左右的迭代(叫“燃烧期”,因为初始值可能远离真实后验),剩下的样本就是联合后验的样本,用来计算参数的均值、置信区间等。
PyMC3里的NUTS采样是怎么回事?
你读的PyMC3书里可能直接用pm.sample(),背后用的是NUTS采样。NUTS不需要你手动推导每个条件后验的解析形式——它用**哈密顿蒙特卡洛(HMC)**的方法,通过模拟物理系统的运动来高效采样,尤其适合高维参数空间。
但底层逻辑和Gibbs采样一致:NUTS会自动处理每个参数的条件后验,通过自适应调整步长和路径长度,高效遍历联合后验分布。针对你的例子,PyMC3的代码大概是这样(简化版):
import pymc3 as pm # 假设你的数据已经准备好了:y = [y1,y2,y3], x = [x1,x2,x3,x4,x5], z = [z1,z2] with pm.Model() as hierarchical_model: # 超先验 mu = pm.Normal('mu', mu=0, sd=10) # 弱信息先验 tau = pm.HalfCauchy('tau', beta=5) # 常用的弱信息先验 # 层次参数:θ₁,θ₂,θ₃ theta = pm.Normal('theta', mu=mu, sd=tau, shape=3) theta1, theta2, theta3 = theta # 观测数据的似然函数 pm.Normal('y_obs', mu=theta1, sd=1, observed=y) # σ_y假设为1,可替换成变量 pm.Normal('x_obs', mu=theta2, sd=1, observed=x) pm.Normal('z_obs', mu=theta3, sd=1, observed=z) # 启动采样:10000次采样,2000次燃烧期 trace = pm.sample(10000, tune=2000, cores=2)
运行后,trace里就包含了所有参数的后验样本,你可以用pm.summary(trace)看统计量,pm.traceplot(trace)看采样的收敛情况。
关键要点总结
- 层次模型采样的核心是把复杂的联合后验拆成简单的条件后验,逐个参数采样
- 简单的条件后验(比如正态分布)可以直接采样,复杂的可以用NUTS这类自适应采样器自动处理
- 样本数量直接影响单个θᵢ的后验:数据越多,θᵢ的后验越集中(方差越小)
- 超参数
μ和τ是所有θᵢ的“纽带”——共享超先验让小样本的θ₃可以借用θ₁、θ₂的信息,避免极端估计
内容的提问来源于stack exchange,提问作者Iltl

