欢迎光临
我们一直在努力

Savage-Dickey密度比深解:bayestestR贝叶斯因子是怎么算出来的(附代码实现)

Savage-Dickey密度比深解:bayestestR贝叶斯因子是怎么算出来的(附代码实现)

【免费下载链接】bayestestR :ghost: Utilities for analyzing Bayesian models and posterior distributions 【免费下载链接】bayestestR 项目地址: https://gitcode.com/gh_mirrors/ba/bayestestR

你是否好奇 R 语言中 bayestestR 包输出的**贝叶斯因子(Bayes Factor)**背后究竟藏着什么?本文将用大白话拆解 Savage-Dickey 密度比原理,带你从源码层面看懂贝叶斯因子是怎么算出来的,并附上可直接运行的代码实现,帮助新手快速掌握这一贝叶斯统计核心工具 🔍

bayestestR包官方横幅:展示贝叶斯因子计算与后验密度估计工具包

一、什么是贝叶斯因子?为什么需要 Savage-Dickey 密度比?

贝叶斯因子(BF) 是衡量"数据支持哪个假设"的比值:BF > 1 表示数据更支持备择假设,BF < 1 表示数据更支持零假设。它相当于 p 值的双向替代品——既能给出"证据支持零假设"的结论,也能量化支持的程度。

但严格计算贝叶斯因子需要对边际似然做高维积分,计算代价极高。幸运的是,Wagenmakers 等人(2010)提出的 Savage-Dickey 密度比提供了一个优雅的"捷径":

只需比较先验分布和后验分布在零假设点上的"密度值",二者相除就是贝叶斯因子!

换句话说:零假设点(通常是 0)在后验中的密度相对先验"缩水"了多少,数据就有多反对零假设 📉

![bayestestR贝叶斯因子计算原理图:Savage-Dickey密度比通过比较先验与后验在零假设点的密度得出](https://raw.gitcode.com/gh_mirrors/ba/bayestestR/raw/77d649a2f55481e0b863c0d35b2a14dba7f44afb/paper/JOSS paper files/Figure3.png?utm_source=gitcode_repo_files))

图:面板 C 即 Savage-Dickey 密度比示意图——虚线为先验密度,黄色实线为后验密度,蓝点与红点分别是两者在零假设点(0)处的密度值,二者的比值就是贝叶斯因子。

二、Savage-Dickey 密度比原理:3 个关键步骤

步骤 1:用"密度"代替"概率"

零假设是"参数恰好等于 0"。连续分布中,单点的概率恒为 0,没法直接比较。于是我们改用概率密度:密度越高,说明该值在分布中越"可信"。

步骤 2:在零假设点上取两个密度

  • 对先验分布做密度估计,取 $x=0$ 处的密度值 $\\pi(0)$
  • 对后验分布做密度估计,取 $x=0$ 处的密度值 $\\pi(0\\mid D)$

步骤 3:两个密度相除

$$BF_{10} = \\frac{\\pi(0)}{\\pi(0\\mid D)}$$

  • 若数据让后验"远离"了 0 → 后验在 0 处密度变低 → BF > 1(支持备择假设)
  • 若数据让后验"聚焦"到 0 → 后验在 0 处密度升高 → BF < 1(支持零假设)

bayestestR贝叶斯因子示例:先验与后验分布密度对比及零假设点密度

图:先验(虚线)与后验(黄色)密度对比。后验整体右移、变窄,其在零假设点处的密度相对先验大幅下降——这正是"数据反对零假设"的几何直观。

三、源码解析:bayestestR 是怎么一步步算出来的?

下面跟着源码走一遍完整流程(文件路径均相对项目根目录)。

1. 入口函数:智能分派

bayesfactor() 是统一入口,它会根据输入自动分派到合适的实现(见 R/bayesfactor.R 第 63–86 行):

# R/bayesfactor.R(节选)
bayesfactor <- function(…, prior = NULL, direction = "two-sided",
null = 0, hypothesis = NULL, …) {
mods <- list(…)

if (length(mods) > 1) {
bayesfactor_models(…) # 多个模型 → 模型比较 BF
} else if (is.null(hypothesis)) {
bayesfactor_parameters( # 单参数 → Savage-Dickey 密度比
…, prior = prior, direction = direction, null = null
)
} else {
bayesfactor_restricted(…) # 带假设 → 有序限制 BF
}
}

2. 核心实现:logspline 密度估计 + 密度比

真正干活的是内部函数 .logbayesfactor_parameters()(R/bayesfactor_parameters.R 第 531–576 行)。简化后的核心逻辑如下:

# R/bayesfactor_parameters.R(核心逻辑,简化版)
.logbayesfactor_parameters <- function(posterior, prior, direction = 0, null = 0, …) {

if (length(null) == 1) {
# —— 点零假设:Savage-Dickey 密度比 ——
relative_loglikelihood <- function(samples) {
f_samples <- .logspline(samples) # ① logspline 拟合密度
d_samples <- logspline::dlogspline(null, f_samples, log = TRUE) # ② 取零假设点处的对数密度
if (direction < 0) {
norm_samples <- logspline::plogspline(null, f_samples) # ③ 单侧检验的归一化
} else if (direction > 0) {
norm_samples <- 1 – logspline::plogspline(null, f_samples)
} else {
norm_samples <- 1
}
d_samples – log(norm_samples)
}
} else {
# —— 区间零假设:比较区间内外的"相对可信度"变化 ——
# 用 logspline::plogspline() 计算区间概率,再做对数比值
}

# 关键一步:先验与后验的差值 = 对数贝叶斯因子
relative_loglikelihood(prior) – relative_loglikelihood(posterior)
}

逐行拆解 3 个要点:

步骤代码含义
.logspline(samples) 用 logspline 算法(单调 B 样条)从 MCMC 样本中拟合平滑密度曲线,比简单核密度更精准
dlogspline(null, …) 提取零假设点(默认 0)处的对数密度
plogspline(…) 单侧检验(direction = "left"/"right")时,把非零一侧的概率归一化为 1,实现有序限制

最后第 575 行 relative_loglikelihood(prior) – relative_loglikelihood(posterior) 一行完成"先验密度比后验密度"——在对数空间相除变成相减,数值更稳定。函数返回的是 log_BF,用 as.numeric() 可转回普通 BF 值。

多参数模型则在外层 bayesfactor_parameters.data.frame()(第 475–484 行)中逐列循环调用上述核心函数,输出每个参数一行的 BF 表。

四、动手实践:3 行代码算出贝叶斯因子 💡

只需先验和后验的 MCMC 样本(向量、数据框或 stanreg/brmsfit 模型对象均可):

library(bayestestR)

# 模拟 1000 个先验 / 后验样本
set.seed(123)
prior <- distribution_normal(1000, mean = 0, sd = 1)
posterior <- distribution_normal(1000, mean = 0.5, sd = 0.3)

# ① 点零假设 BF(默认 null = 0,即 Savage-Dickey 密度比)
bayesfactor_parameters(posterior, prior = prior, verbose = FALSE)

# ② 区间零假设 BF(ROPE 式检验,null 为区间)
bayesfactor_parameters(posterior, prior = prior,
null = c(-0.1, 0.1), verbose = FALSE)

# ③ 单侧(方向性)BF
bayesfactor_parameters(posterior, prior = prior,
direction = "right", verbose = FALSE)

bayesfactor_parameters()、bayesfactor_pointnull()、bayesfactor_rope() 是同一函数的三种默认配置(见 R/bayesfactor_parameters.R 第 195–241 行)。

JASP界面中的贝叶斯ANOVA输出示例:展示模型比较与效应包含贝叶斯因子结果表

图:主流工具(如 JASP)输出的贝叶斯 ANOVA 结果表,BF₁₀ 列的数值正是由上述 Savage-Dickey / 边际似然方法计算得到。

五、结果解读清单:贝叶斯因子数值怎么看?

输出结果默认是 log_BF(对数 BF),用 as.numeric() 提取 BF 值后,可对照下表解读:

BF₁₀ 范围证据强度说明
< 1/3 弱证据支持零假设 数据让零假设点密度升高
1/3 ~ 1 可忽略 证据极弱,两边都不明显
1 ~ 3 轶事级证据反对零假设 轻微偏向备择假设
3 ~ 10 中等证据 有一定支持
10 ~ 30 强证据 数据明显支持备择假设
30 ~ 100 很强证据 后验已大幅偏离零假设点
> 100 极强证据 后验密度在 0 处几乎"塌陷"

📌 小技巧:log 尺度上,log_BF ≈ 1 约相当于 BF ≈ 2.7(中等证据起点),log_BF ≈ 2.3 约相当于 BF ≈ 10(强证据起点),读数更方便。

六、避坑指南:4 个新手最容易踩的坑 ⚠️

  • 样本量要够:源码中明确警告(R/bayesfactor_parameters.R 第 468–473 行),当样本少于 40,000 时会提示"Bayes factors might not be precise"。密度估计在分布"尾部/峰部"对样本量很敏感,建议 MCMC 至少跑 4 万条后验样本。

  • 先验必须正确提供:BF 衡量的是"先验 → 后验"的信念变化。若 prior = NULL,函数会警告并默认把后验当前验,结果毫无意义。对 stanreg/brmsfit 模型可用 unupdate() 自动生成纯先验样本(见 R/unupdate.R)。

  • 它只是"近似":Savage-Dickey 密度比是局部替代假设(在零假设点附近取先验)下的贝叶斯因子近似(Wagenmakers et al., 2010;Heck, 2019 讨论了回归参数场景的注意点)。若先验很宽(如 t 分布重尾),BF 可能受先验形状影响较大。

  • 有序限制 BF 只适用于事先假设:bayesfactor_restricted() 用于"参数 A > B"这类预设的方向性假设,不能事后挑选比较对象(见 R/bayesfactor_restricted.R 第 3–4 行的注释提醒)。

  • 七、延伸阅读:项目文件导航 📚

    想深入源码与文档,可从以下路径入手(相对项目根目录):

    • R/bayesfactor_parameters.R —— Savage-Dickey 密度比核心实现
    • R/bayesfactor_restricted.R —— 有序限制 / 方向性假设的 BF 计算
    • R/bayesfactor_models.R —— 多模型边际似然比较
    • R/estimate_density.R —— 密度估计封装(支持 kernel / logspline 等方法)
    • R/unupdate.R —— 从后验模型"还原"先验样本
    • vignettes/bayes_factors.Rmd —— 官方贝叶斯因子完整教程(含推导)
    • man/bayesfactor_parameters.Rd —— 函数参考文档
    • tests/testthat/test-bayesfactor_parameters.R —— 相关单元测试

    想从源码获取并本地构建,可执行:

    git clone https://gitcode.com/gh_mirrors/ba/bayestestR


    总结:bayestestR 的贝叶斯因子计算并不神秘——本质就是"logspline 拟合先验与后验密度 → 取零假设点处的密度 → 相除"三步。理解了 Savage-Dickey 密度比,你就掌握了从 R 的 MCMC 样本直接推断假设证据强度的钥匙 🗝️

    【免费下载链接】bayestestR :ghost: Utilities for analyzing Bayesian models and posterior distributions 【免费下载链接】bayestestR 项目地址: https://gitcode.com/gh_mirrors/ba/bayestestR

    创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

    赞(0)
    未经允许不得转载:171主机测评 » Savage-Dickey密度比深解:bayestestR贝叶斯因子是怎么算出来的(附代码实现)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址