大数跨境

导师:“你用Codex写了贝叶斯预测?”我:“Beta分布跑通了!”导师:“要搞懂共轭先验、后验更新和α、β参数!”

导师:“你用Codex写了贝叶斯预测?”我:“Beta分布跑通了!”导师:“要搞懂共轭先验、后验更新和α、β参数!” 机器学习和人工智能AI
2026-10-26
3

哈喽,大家好~

今儿和大家聊聊,Beta 分布~

首先,我们要清楚的一点是,Beta 分布是定义在区间   上的一类概率分布。

Beta 分布通常用来描述一个“概率”的不确定性:比如我们不知道一枚硬币正面朝上的概率   是多少,我们可以把对   的不确定性用一个 Beta 分布来刻画。

Beta 分布有两个参数,通常写作 Beta ,可以理解为“虚拟的成功次数”与“虚拟的失败次数”。

  • (alpha)像是“先验里假设看到了   次成功”;
  • (beta)像是“先验里假设看到了   次失败”。

Beta 分布的概率密度函数(pdf)为:

其中   是 Beta 函数(归一化常数)。

Beta 分布的平均值和方差为:

一个非常棒的性质叫“共轭性”:如果先验是 Beta ,观测到了   次成功、  次失败(独立同分布 Bernoulli / Binomial 的观测),则后验仍然是 Beta 分布:

所以后验是 Beta 。这意味着你只需要把观测的成功数和失败数分别加到 alpha、beta 上就完成了贝叶斯更新,计算极其简单、直观。

另外,如果我们想预测在接下来的   次试验中会有多少成功,贝叶斯预测分布就是 Beta-Binomial 分布(边缘化了  ):

直观上来说,先验越集中(  大)表示“我们对   很有把握”;先验越平坦( )表示无信息先验(均匀分布)。

随着数据增加,后验会越来越集中且收敛到真实频率(如果数据是 iid 且模型正确),这就是贝叶斯学习的“从先验到由数据主导”的过程。

完整案例

目标:w哦们用一组二值数据(Bernoulli),假设真实的 p 有两个阶段的变化(先为 0.2,后变为 0.7),我们用 Beta 先验做顺序更新,观察后验如何随时间变化、以及预测分布如何表现。

import torch
import torch.distributions as D
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="whitegrid")

torch.manual_seed(0)
np.random.seed(0)

# 1. 数据集:长度 N,前半段 p0,后半段 p1
N = 200
p0, p1 = 0.2, 0.7
data = np.zeros(N, dtype=int)
data[:N//2] = np.random.binomial(1, p0, size=N//2)
data[N//2:] = np.random.binomial(1, p1, size=N - N//2)

# 2. 设定先验(可以尝试不同比例)
alpha0, beta0 = 2.0, 2.0   # 一个有点信息的先验(有偏好均衡但不太强)
# alpha0, beta0 = 1.0, 1.0  # 无信息均匀先验

# 预备网格用于绘制密度
p_grid = np.linspace(0.001, 0.999, 1000)

# 3. 顺序更新:我们在若干 checkpoint 处保存后验参数(用于作图)
checkpoints = [0, 5, 20, 50, 100, 150, 200]  # 包括初始和最终
alpha_t, beta_t = alpha0, beta0
saved = []
k_sum = 0
for t in range(1, N+1):
    if data[t-1] == 1:
        k_sum += 1
    # 在线更新(累积)
    alpha_t = alpha0 + k_sum
    beta_t = beta0 + (t - k_sum)
    if t in checkpoints:
        saved.append((t, alpha_t, beta_t))

# 最终后验
alpha_final, beta_final = alpha_t, beta_t

# 计算密度函数(使用 Beta 的 pdf 公式)
from scipy.special import betaln, beta as beta_fn, comb, gammaln

def beta_pdf_grid(alpha, beta, p_grid):
    # 使用 scipy.special.gammaln 稳定计算
    lnC = - (gammaln(alpha) + gammaln(beta) - gammaln(alpha+beta))
    ln_pdf = lnC + (alpha-1)*np.log(p_grid) + (beta-1)*np.log(1-p_grid)
    return np.exp(ln_pdf)

# 4. 图 1: 初始先验 vs 最终后验
plt.figure(figsize=(10,6))
prior_pdf = beta_pdf_grid(alpha0, beta0, p_grid)
post_pdf_final = beta_pdf_grid(alpha_final, beta_final, p_grid)
plt.plot(p_grid, prior_pdf, label=f'Prior Beta({alpha0},{beta0})', color='tab:blue', lw=2)
plt.plot(p_grid, post_pdf_final, label=f'Posterior Beta({alpha_final:.1f},{beta_final:.1f})', color='tab:orange', lw=2)
plt.fill_between(p_grid, 0, prior_pdf, color='tab:blue', alpha=0.08)
plt.fill_between(p_grid, 0, post_pdf_final, color='tab:orange', alpha=0.08)
plt.xlabel('p')
plt.ylabel('Density')
plt.title('Prior vs Final Posterior Density')
plt.legend()
plt.tight_layout()
plt.show()

# 5. 图 2: 后验随时间演化(在 checkpoints 时间点绘制多条密度)
plt.figure(figsize=(10,6))
colors = sns.color_palette("Set1", n_colors=len(saved))
for i,(t, a, b) in enumerate(saved):
    pdf_i = beta_pdf_grid(a, b, p_grid)
    plt.plot(p_grid, pdf_i, label=f't={t}, α={a:.1f}, β={b:.1f}', color=colors[i], lw=1.6)
plt.xlabel('p')
plt.ylabel('Density')
plt.title('Posterior evolution at checkpoints')
plt.legend(loc='upper left', bbox_to_anchor=(1.02,1))
plt.tight_layout()
plt.show()

# 6. 图 3: 后验预测(Beta-Binomial)对未来 m 次试验的分布
# 计算 Beta-Binomial PMF: P(K=k) = C(m,k) * B(alpha+k, beta+m-k) / B(alpha,beta)
def beta_binomial_pmf(m, alpha, beta):
    ks = np.arange(0, m+1)
    # 使用 betaln 以保持数值稳定
    ln_coeff = gammaln(m+1) - (gammaln(ks+1) + gammaln(m-ks+1))
    ln_p = ln_coeff + betaln(alpha + ks, beta + m - ks) - betaln(alpha, beta)
    return ks, np.exp(ln_p)

plt.figure(figsize=(10,6))
for m, col in zip([1, 5, 10], ['tab:green', 'tab:red', 'tab:purple']):
    ks, pmf = beta_binomial_pmf(m, alpha_final, beta_final)
    plt.plot(ks, pmf, marker='o', color=col, label=f'm={m}')
plt.xlabel('Number of successes K in next m trials')
plt.ylabel('P(K=k)')
plt.title('Posterior predictive (Beta-Binomial) with final posterior')
plt.legend()
plt.tight_layout()
plt.show()

# 7. 图 4: 不同先验强度(alpha+beta)对后验均值与 95% CI 宽度的影响(热力图)
# 我们在一个网格上改变 alpha0, beta0 的大小,但保持均衡形状(alpha0=beta0)
grid_vals = np.linspace(0.5, 20, 40)  # 先验强度范围
mean_grid = np.zeros((len(grid_vals),))
ci95_width = np.zeros((len(grid_vals),))
observed_success = int(np.sum(data[:100]))   # 比如只看前 100 个观测
n_obs = 100
for i, a0 in enumerate(grid_vals):
    b0 = a0
    a_post = a0 + observed_success
    b_post = b0 + (n_obs - observed_success)
    mean = a_post / (a_post + b_post)
    # 95% credible interval via Beta percent point (use scipy)
    from scipy.stats import beta as sp_beta
    low, high = sp_beta.ppf([0.025, 0.975], a_post, b_post)
    mean_grid[i] = mean
    ci95_width[i] = high - low

fig, ax = plt.subplots(1,2, figsize=(12,4))
ax[0].plot(grid_vals, mean_grid, color='tab:cyan')
ax[0].set_title('Posterior mean vs prior strength (alpha=beta)')
ax[0].set_xlabel('alpha=beta (prior strength)')
ax[0].set_ylabel('Posterior mean')

ax[1].plot(grid_vals, ci95_width, color='magenta')
ax[1].set_title('95% CI width vs prior strength (alpha=beta)')
ax[1].set_xlabel('alpha=beta (prior strength)')
ax[1].set_ylabel('Width of 95% CI')
plt.tight_layout()
plt.show()

图 1:先验 vs 最终后验密度

展示我们在观察了全部 N=200 条数据之后,后验分布相对于最初先验的变化。

如果最终后验的峰位移到一个特定位置(例如接近 0.7 或 0.2),说明数据强烈支持该区域的 p 值。后验峰比先验更尖,说明数据使我们的不确定性减少(方差变小)。

在我们的示例中,由于数据前后段 p 有变化、且后段占一半样本,最终后验会综合两段信息,通常峰会落在两个阶段加权效果附近(若后段样本更多或者成功比率更集中,会往后段靠拢)。

图 2:后验随时间演化

在若干时间点(如 t=5,20,50,100,150,200)绘制后验密度曲线,可以看到后验如何随着观测逐步更新、收敛或发生跳变。

在前半段(p=0.2)时,后验会逐渐集中到偏小的 p 值;一旦进入后半段(p=0.7),随着更多成功样本的进入,后验会逐步向 0.7 移动,可能出现明显的质变(峰值移动)。

这是理解顺序(在线)贝叶斯更新最直观的图:数据如何一步一步改变量化的信念。

图 3:后验预测(Beta-Binomial)对未来 m 次试验的分布

固定用当前(最终)后验作为 p 的不确定性分布,计算在未来 m 次独立试验中成功次数 K 的分布(Beta-Binomial)。

当 m 很小(例如 m=1),分布可能集中在 K=0 或 1 两点上(取决于后验均值),但概率并不极端(因为后验还有不确定性)。

当 m 增加(m=5,10),分布变得更宽,峰值位置大体接近 m * posterior_mean,但形状反映了后验的不确定性:如果后验很确定,Beta-Binomial 会接近 Binomial;若后验不确定,分布更宽、峰更平。

这张图告诉我们:贝叶斯方法不仅给出参数的后验,还能给出对未来观测的完整概率预测。

图 4:不同先验强度对后验均值与 95% CI 宽度的影响

固定先验形状(例如对称,alpha=beta),但改变其强度(alpha+beta),看看在观察前 100 个样本后,后验均值如何随先验强度变化,以及 95% 置信区间宽度如何变化。

当先验强度很小(例如 alpha=beta≈0.5~2),后验主要由数据主导,后验均值接近样本频率,CI 依数据量收窄;当先验强度很大(例如 alpha=beta=20),先验会“压制”数据,后验均值会被拉回到先验均值(在对称先验下为 0.5),CI 也可能较窄(因为先验本身带来了假的“数据”)。

这张图帮助我们理解“先验的强弱”如何影响学习:先验不该随意设得过强,除非你确实有大量外部信息。

几点建议与常见误区

先验不是随便选的“主观偏见”就不好:合理的弱信息先验能稳定推断,尤其在数据量少时非常重要。但也要避免把先验设得过强而掩盖数据证据。

Beta 分布适合概率参数   的情况(Bernoulli / Binomial 模型)。如果问题不是二值的,找相应的共轭家族(例如 Dirichlet 适用于多分类概率向量)。

在实际的非静态环境(像本例的分段 p)下,标准的 Beta 更新会把历史数据等同对待,可能导致“滞后”或“平滑过度”。这时可以考虑使用滑动窗口、加权更新或状态空间模型(如隐马模型或动态贝叶斯网络)来应对概念漂移。

置信区间(Credible Interval)和频率学置信区间是不同概念:贝叶斯的 95% CI 表示在后验分布下参数落入区间的概率为 0.95,而非“在重复抽样下包含真实参数的概率为 0.95”。

最后

Beta 分布是贝叶斯建模中用于描述 [0,1] 范围参数(概率)最常见、最直观的工具。它和 Bernoulli/Binomial 的共轭性令更新极其简单,适合在线学习与快速实验。

若要深入学习 Dirichlet 分布(Beta 的多维推广),学习 Beta-Bernoulli 模型在 A/B 测试、拉普拉斯平滑中的应用,在动态环境中研究贝叶斯滤波、粒子滤波或状态空间模型来处理概率随时间变化的问题。

非常建议大家把本文中的代码拿去跑一跑,尝试改变先验、改变数据结构(例如把后半段的 p 换成 0.9 或把变化点移到不同位置),观察后验和预测的变化,这是理解贝叶斯直觉最有效的方式~

【声明】内容源于网络
0
0
机器学习和人工智能AI
让我们一起期待 AI 带给我们的每一场变革!推送最新行业内最新最前沿人工智能技术!
内容 435
粉丝 0
机器学习和人工智能AI 让我们一起期待 AI 带给我们的每一场变革!推送最新行业内最新最前沿人工智能技术!
总阅读8.9k
粉丝0
内容435