贝叶斯建模实战指南:从原理到模型选择、评估与平均

author: 周均扬

date:2026.06.28


1. 为什么选择贝叶斯建模?

在数据科学和工程实践中,我们经常面对小样本、不确定性高、需要融入领域知识的场景。传统频率学派(Frequentist)方法擅长给出“点估计”和p-value,但往往难以自然地量化预测不确定性或融合先验信息。

贝叶斯建模的核心哲学是:一切皆概率。它把参数视为随机变量,通过 “先验信念 + 数据更新 → 后验信念” 的方式进行推理,最终得到完整的 后验分布,而非单一数值。

贝叶斯 vs 频率学派核心对比:

维度 频率学派(Frequentist) 贝叶斯(Bayesian) 实际影响
参数本质 固定未知常数 随机变量(有分布) 贝叶斯可直接给出参数概率
不确定性表达 置信区间(长期频率解释) 可信区间(当前信念概率) 贝叶斯更直观
先验信息 不使用(或隐含) 显式融入领域知识 贝叶斯适合小样本
模型比较 AIC/BIC、交叉验证 WAIC、LOO-CV、Bayes Factor、模型平均 贝叶斯工具更丰富
预测 点预测 + 区间 完整预测分布(含不确定性) 贝叶斯决策更稳健
计算复杂度 通常较低 较高(需采样) 现代工具已大幅降低门槛

一句话总结:频率学派问“这个参数在无限重复实验中是多少?”;贝叶斯问“在当前数据和先验下,这个参数最可能在什么范围?”


2. 贝叶斯建模的标准流程(五步法)

步骤1:定义模型(先验 + 似然)

步骤2:计算/采样后验

步骤3:后验诊断与可视化

步骤4:模型选择、比较与平均

步骤5:后验预测与决策


3. 实战例子:电池 SOH 与低谷电压的高斯建模

问题背景:锂电池老化后,低谷电压与 SOH 呈非单调“山峰”关系。我们用4个实测点建模,目标是预测不同 SOH 下的电压并量化不确定性。

数据:

候选模型:

  1. 高斯钟形模型: \(V = A * \exp\left( -\frac{(SOH-\mu)^2}{2\sigma^2} \right) + b\)
    • A:峰值幅度(早期老化效应)
    • μ:峰值位置(≈90.3%,老化转折点)
    • σ:峰宽
    • b:基础电压
  2. 二次多项式(对比基准):简单但峰值捕捉较弱。

先验设置(强截断正态示例):

Python代码例子

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.optimize import curve_fit

# 数据
soh = np.array([100.0, 90.65, 83.19, 80.66])
voltage = np.array([2.7103, 2.7501, 2.7333, 2.7266])

def gaussian(x, A, mu, sigma, b):
    return A * np.exp( - (x - mu)**2 / (2 * sigma**2) ) + b

def log_likelihood_pointwise(theta, x_i, y_i, sigma_noise=0.005):
    y_pred = gaussian(x_i, *theta)
    return -0.5 * ((y_i - y_pred)/sigma_noise)**2 - np.log(sigma_noise * np.sqrt(2*np.pi))

# 1. 获取后验样本(Bootstrap + 强截断先验)
np.random.seed(42)
n_boot = 2000
boot_params = []
for _ in range(n_boot):
    idx = np.random.choice(len(soh), len(soh), replace=True)
    try:
        p = curve_fit(gaussian, soh[idx], voltage[idx], p0=[0.04, 90, 6, 2.71], maxfev=5000)[0]
        A, mu, sigma, b = p
        if 0.035 < A < 0.048 and 87 < mu < 93.5 and 4.5 < sigma < 7.8 and 2.707 < b < 2.714:
            boot_params.append(p)
    except:
        pass
boot_params = np.array(boot_params)

# 2. 点式对数似然矩阵
n_data = len(soh)
log_lik_matrix = np.array([[log_likelihood_pointwise(theta, soh[i], voltage[i]) 
                            for i in range(n_data)] for theta in boot_params])

# 3. WAIC
lppd = np.sum(np.log(np.mean(np.exp(log_lik_matrix), axis=0)))
p_waic = np.sum(np.var(log_lik_matrix, axis=0))
WAIC = -2 * (lppd - p_waic)
print(f"WAIC = {WAIC:.2f}, p_waic = {p_waic:.2f}")

# 4. LOO-CV 近似
elpd_loo = np.sum(np.log(np.mean(np.exp(log_lik_matrix), axis=0)))
LOO = -2 * elpd_loo
print(f"LOO ≈ {LOO:.2f}")

# 5. PPC(后验预测检验)
n_rep = 500
y_rep = np.array([np.random.normal(gaussian(soh, *theta), 0.005) 
                  for theta in boot_params[np.random.randint(len(boot_params), size=n_rep)]])

plt.figure(figsize=(10, 6))
sns.kdeplot(voltage, color='red', linewidth=3, label='Observed', fill=True)
for r in range(min(100, n_rep)):
    sns.kdeplot(y_rep[r], color='purple', alpha=0.1, linewidth=1)
sns.kdeplot(np.mean(y_rep, axis=0), color='blue', linewidth=2.5, label='Mean Replicated')
plt.title('Posterior Predictive Check (PPC)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

4. 模型选择与评估工具详解

1. WAIC 与 LOO-CV

实际结果(强先验下):

2. PPC(后验预测检验)

PPC 是检验模型是否“像真数据”的最直观工具:从后验中抽取参数,生成大量“假数据”,对比真实数据分布。

典型 PPC 图特征(高斯模型):

(运行代码可生成高清 PPC 图,当前高斯模型表现优秀。)

3. 参数后验可视化(更多图表示例)

这些图帮助我们理解参数依赖性和先验的影响。


5. 模型平均(Model Averaging)实战代码

当多个模型都有一定合理性时,不要只挑“最好”的,而是加权平均,权重基于 WAIC/LOO。

import numpy as np

# 假设已有两个模型的后验 log_lik_matrix_gauss 和 log_lik_matrix_quad
# 计算 WAIC(简化)
def compute_waic(log_lik_mat):
    lppd = np.sum(np.log(np.mean(np.exp(log_lik_mat), axis=0)))
    p_waic = np.sum(np.var(log_lik_mat, axis=0))
    return -2 * (lppd - p_waic)

waic_g = compute_waic(log_lik_matrix_g)  # 高斯
waic_q = compute_waic(log_lik_matrix_q)  # 二次

# 模型权重(基于 WAIC,类似 stacking)
delta_waic = waic_g - waic_q
weight_g = 1 / (1 + np.exp(delta_waic / 2))   # 简化 softmax
weight_q = 1 - weight_g

print(f"高斯模型权重: {weight_g:.3f}")
print(f"二次模型权重: {weight_q:.3f}")

# 模型平均预测(示例)
new_soh = np.array([95, 85, 75])
pred_g = np.mean([gaussian(new_soh, *p) for p in boot_params_g], axis=0)
pred_q = np.mean([quad(new_soh, *p) for p in boot_params_q], axis=0)
pred_avg = weight_g * pred_g + weight_q * pred_q

print("模型平均预测:", pred_avg)

优势:模型平均通常比单一“最佳”模型预测性能更好,且自动处理模型不确定性。


6. 频率学派 vs 贝叶斯:更深入对比

何时选贝叶斯?


7. 实用工具栈与最佳实践

推荐工具:

最佳实践 checklist:

  1. 始终做 PPC。
  2. 报告 WAIC/LOO + Pareto k 诊断。
  3. 尝试不同先验强度,观察稳健性。
  4. 考虑模型平均而非单一选择。
  5. 用 ArviZ 进行模型比较和权重计算。

8. 结语与行动建议

贝叶斯建模不是“黑箱魔法”,而是把不确定性说清楚的科学框架。通过 WAIC、LOO-CV、PPC 和模型平均,我们可以更可靠地选择模型、量化风险,并做出更好决策。

行动建议:

  1. 复制本文完整代码,跑通高斯模型。
  2. 生成 PPC、pairplot 和相关性热图。
  3. 尝试模型平均代码,比较单一模型 vs 平均模型的预测。
  4. 本地安装 pymc + arviz,体验一键 LOO 和模型比较。

贝叶斯建模的核心不是计算,而是思维方式的转变——从“找到答案”转向“不断更新对世界的信念”。