JAGS中创建用户自定义分布的可行性与操作方法问询
JAGS非内置分布采样与自定义分布实现方法
JAGS原生不支持直接通过模型语法声明全新的命名自定义分布,但有两种成熟的方案可以实现从非内置分布中采样参数的需求:
- 使用通用似然适配技巧(zeros/ones trick,无需扩展JAGS本身,适合临时需求)
这是最常用的轻量方案,核心思路是引入伪观测数据,将自定义分布的对数似然转换为JAGS内置分布的似然形式,让MCMC采样时能正确计算后验:- zeros trick:基于泊松分布实现,适用于所有可以写出对数似然的自定义分布
操作步骤:- 先计算你的自定义分布在当前参数取值下的对数似然值
llik - 设定一个常数
C,取值要略大于所有可能情况下-llik的最大值,保证泊松分布参数始终为正 - 在模型中加入代码:
dummy ~ dpois(-llik + C),同时给伪变量dummy传入固定观测值0
- 先计算你的自定义分布在当前参数取值下的对数似然值
- zeros trick:基于泊松分布实现,适用于所有可以写出对数似然的自定义分布
举个简单的实现示例,假设你需要对观测值y拟合自定义的拉普拉斯分布,模型代码示例如下:
model { # 先验设定 mu ~ dnorm(0, 1e-3) sigma ~ dunif(0, 10) # 计算拉普拉斯分布的对数似然 llik <- log(0.5) - abs(y - mu) / sigma # zeros trick实现 C <- 1000 # 取值需保证 -llik + C 始终为正 dummy ~ dpois(-llik + C) }
ones trick:基于伯努利分布实现,原理和zeros trick类似
操作步骤:- 计算自定义分布的对数似然值
llik - 设定常数
C,取值略大于所有可能情况下llik的最大值,保证exp(llik - C)的结果在0到1之间 - 在模型中加入代码:
dummy ~ dbern(exp(llik - C)),同时给伪变量dummy传入固定观测值1
- 计算自定义分布的对数似然值
编写JAGS扩展模块(适合需要频繁复用的自定义分布)
如果某个自定义分布需要在多个项目中反复使用,可以基于JAGS的模块开发接口用C编写自定义分布的实现,编译为动态链接库后,在运行JAGS时用load.module()命令加载,之后就可以和内置分布一样直接调用,采样效率比前一种trick更高,但需要掌握基础的C开发能力和JAGS模块开发规则。
使用zeros/ones trick时要注意校验对数似然的计算逻辑,同时合理设置常数C的取值,C过大会导致数值精度损失,过小则会出现似然计算错误,进而导致采样链不收敛。
内容的提问来源于stack exchange,提问作者Ridwan Adejumo Suleiman
相关产品推荐
相关产品推荐

