想象你是国宴的主厨,要为上万宾客准备一场甜点盛宴。你手里只有一份“味型配方”——它不是精确到克的配料清单,而是一张比例图谱:甜味出现 30%,果香 20%,咸香 50%。你要做的,是不断从这个图谱里“抽”出原料样本来试菜。可问题来了:配方图谱有好有坏,有的反手就能抽,有的连长什么样都画不出来。于是你练就了五门手艺:查着累积表闭眼抽(逆变换采样)、搬来原料逐块质检(拒绝采样)、按重要程度给原料加权(重要性采样)、把仓库分区管理(分层采样)、最后干脆亲自走进厨房随机游走(MCMC)。这篇内容就用这间厨房的故事,把采样方法彻底讲透——看完你就能像主厨一样,面对任何分布都能选出趁手的抽取工具。
采样是概率编程、贝叶斯推断和强化学习的底层引擎:掌握它,你才能从“调用 random”进化到“为复杂分布设计抽样器”,这是做 AI 推断与决策系统的核心手艺。
可视化演示
动态演示采样方法的核心机制,通过概览/流程/对比/趋势四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
采样方法:逆变换采 逆变换采样从均匀分布到任意分布 拒绝采样接受拒绝的博弈机制 核心机制可视化 采样方法整体架构与关键组件
采样问题本质
配方书(概率分布)写的不是“白糖 500 克”这种死命令,而是一张口味比例图。你要做的是按这个比例不停地“抽”原料试菜。这就是采样——从概率分布中产生样本。从数学上说,分布 \(p(x)\) 是一张“可能性地图”,每个取值 \(x\) 出现的概率不同。采样工程师的核心问题也随之而来:标准随机数发生器只能吐出 0 到 1 的均匀数,如何让任意分布的“配方”从这些均匀数里长出来?
为什么要费劲采样?因为真实世界里我们关心的往往是某个函数 \(f\) 在分布 \(p\) 下的期望——比如“这款蛋糕的平均成本”“这个策略的平均回报”。理论上要算积分 \(\int f(x)p(x)\,dx\),可惜很多分布(尤其是贝叶斯后验)根本没有解析表达式,积分算不出来。蒙特卡洛方法给了个偷懒招:依靠大数定律,用样本均值替代积分。只要样本量足够大,均值就稳定地逼近真值。
主厨恍然大悟:不需要背下整本配方,只要按比例抽几百份原料试菜,平均口味就等于全场口味。接下来的问题只有一个:配方有难抽有好抽,那究竟怎么把 \(x\) 从 \(p\) 里抽出来?于是有了后面五种武器。
- 目标期望\(\mathbb{E}_p[f(X)]\) 是在分布 \(p\) 下求 \(f(X)\) 的平均值,等同于积分
- 抽样条件\(x_i \sim p(x)\) 表示每个样本都独立地从目标分布 \(p\) 中抽取,即“独立同分布”
- 均值替代\(\dfrac{1}{n}\sum_{i=1}^{n} f(x_i)\) 把无穷积分变成有限求和,\(n\) 越大越接近真值
逆变换采样
配方书里其实藏着一张“累积用料表”——从第 1 页翻到某页,就知道“目前累计用掉的原料占总量的百分比”。主厨要做的极简单:闭眼抽一个 0 到 100 的幸运数,顺着累积表往下找,看这个百分比落在哪种原料那一格,就取那种原料。这张“累积用料表”就是累积分布函数 \(F(x)\),它回答“\(x\) 左边的概率总和是多少”。
均匀随机数 \(U\) 就是那个幸运百分比。逆变换采样说:令 \(X = F^{-1}(U)\),则 \(X\) 恰好服从目标分布。理由很简洁:\(F\) 把任意分布“拉平”成 0 到 1 的均匀分布;反过来,把均匀数塞进反函数 \(F^{-1}\),就还原成目标分布。要验证只需一步:\(\Pr(F^{-1}(U) \le x) = \Pr(U \le F(x)) = F(x)\),这正是“分布函数等于 \(F\)”的定义。
以指数分布为例实操一遍。它的累积分布函数为 \(F(x) = 1 - e^{-\lambda x}\),令它等于 \(u\) 再反解:
主厨很开心:只要配方书有“累积用料表”,闭眼抽数就能出菜。但现实很骨感——正态分布等很多分布的 CDF 没有显式反函数,累积表虽然存在却无法反查。于是主厨需要更硬核的武器。
- 累积函数\(F(x) = 1 - e^{-\lambda x}\) 是指数分布的 CDF,随 \(x\) 从 0 递增到 1
- 解方程令 \(u = 1 - e^{-\lambda x}\),移项把指数项单独放一边
- 取对数两侧取自然对数消去指数,得到 \(x\) 的表达式
- 统一写法因为 \(1 - U\) 与 \(U\) 同分布,也常写成 \(X = -\dfrac{\ln U}{\lambda}\)
拒绝采样
面对一种味道极复杂的原料,配方书的累积表怎么也算不出反函数。主厨换了个思路:先从仓库随便搬一批原料(容易采样的提议分布 \(g\)),然后在案板前逐块质检——符合配方就留下,不符合就扔回去。反复搬、反复验,留下的原料比例自然逼近配方。这个“搬过来、验一下”的过程就是拒绝采样。
拒绝采样需要两样东西:一个易采样的提议分布 \(g\),以及一个包络常数 \(M\),使得 \(M \cdot g(x) \ge f(x)\) 对所有 \(x\) 成立——相当于给目标密度曲线戴上一顶“放大帽”。每次从 \(g\) 抽候选 \(X\),再抽一个均匀判决数 \(U\),若随机点落在目标曲线下方就接受,否则拒绝。
直觉上,接受率等于“目标曲线下的面积除以包络面积”。若 \(g\) 是合法密度(面积为 1),接受率约为 \(1/M\)。\(M\) 越接近 1,说明 \(g\) 越像 \(f\),质检损耗越小;若 \(g\) 和 \(f\) 南辕北辙,绝大多数样本会被扔掉。
主厨叹了口气:质检很万能,但太浪费——仓库原料与配方差别大时,大半物料被扔。到了高维(几百种原料同时配比),接受率随维度指数坍塌,这就是“维度灾难”。主厨需要更精明的算法。
- 候选抽取\(X \sim g(x)\) 先从好采的提议分布中拿一个候选样本
- 接受阈值\(\alpha = \dfrac{f(X)}{M\,g(X)}\) 是这条候选的“质检合格线”,恒小于等于 1
- 随机判决\(U \le \alpha\) 等价于随机点 \((X, U \cdot M)\) 落在目标曲线下方
- 包络约束\(M g(x) \ge f(x)\) 保证 \(\alpha \le 1\),这是正确性的前提
重要性采样
主厨遇到一个更刁钻的需求:不关心原料本身,只关心“某种配方组合下每道菜的平均成本”。若直接按仓库口味抽样估算,算出的成本会有偏差。主厨的聪明做法是:每个样本不看一次就完,而是按“它代表的配方权重”打个折——仓库里多抽的原料就减值,少抽的就增值,最后加权平均。这就是重要性采样。
重要性采样从提议分布 \(q\) 中抽样本,但给每个样本配权重 \(w(x) = p(x)/q(x)\),用加权均值估计目标期望。数学上是个“恒等变形”:在积分里乘一个 \(1\),拆成 \(p/q\),就把对 \(p\) 的期望改写成对 \(q\) 的期望。估计值无偏,且只要权重可控,方差就小。典型场景:目标分布抽不动、提议分布好抽;或者要估计稀罕事件——比如“银行一年亏损超千万”的概率,普通抽样一万次撞不到一次,用偏向尾部的 \(q\) 就能高效命中。
主厨点点头:加权是门手艺——把仓库口味修正成配方口味,零浪费。但权重若失控(\(q\) 太瘦),个别超大权重样本会“绑架”整个估计。主厨还需最后两招。
- 恒等变形乘以 \(\dfrac{p(x)}{q(x)}\) 不改变积分值,只是“换个角度算”
- 期望改写右边变成“在 \(q\) 分布下求 \(\dfrac{p}{q}h\) 的期望”
- 加权均值从 \(q\) 抽 \(n\) 个样本,用权重 \(w_i = p(x_i)/q(x_i)\) 做加权平均
- 风险提醒若 \(q\) 太瘦,个别 \(w_i\) 会爆炸,估计方差飙升甚至失效
分层采样
主厨注意到,厨房原料可以按产地分堆:A 区面粉、B 区奶油、C 区水果。若闭眼从整仓乱抽,可能某次全抽到面粉,水果份额全靠运气。更稳的做法:先按配方把整仓分成几层,每层都保证抽到,再按每层占总量比例加权汇总。这在统计学里就是分层采样。
分层采样把总体按特征划分成 \(k\) 个互不重叠的层,层内分别独立随机抽样。关键在于“层内同质、层间异质”——如果层内样本彼此相似,那么每层只需少量样本就能代表该层;层与层之间的巨大差异则由加权公式确定性地处理掉。直觉上,总方差 = 层内方差 + 层间方差,分层把层间部分完全确定化,只剩层内随机性,方差自然变小。极端情况下层内几乎无差异,方差趋近于零。
主厨把仓库分区管理后,不仅备料均匀,估算还更稳——这就是“用结构换方差”。但它要求你知道层的信息(比如各层占比)。如果连目标长什么样都说不清,就要祭出终极武器 MCMC 了。
- 层划分\(N_j\) 是第 \(j\) 层的大小,\(N = \sum_{j=1}^{k} N_j\) 是总体大小
- 层内均值\(\bar{y}_j\) 是对第 \(j\) 层抽 \(n_j\) 个样本算出的平均
- 加权汇总按层占比 \(\dfrac{N_j}{N}\) 加权求和,层越大话语权越大
- 方差来源层间方差不再进入随机误差,只在层内波动
MCMC采样
宴会越来越庞大,配方从一维的“甜咸比例”变成几百维的“上千种原料配比”,密度函数像连绵山脉,几乎不可能写出解析式。主厨放弃“一次抽一份”的快递模式,改为亲自走进厨房:从当前货架出发,小步走到隔壁尝一口,口味对了就留下,不对就退回原位。就这么一步一停地逛,逛得越久,站过次数越多的货架,越接近配方的高概率区。这就是马尔可夫链蒙特卡洛(MCMC)。
MCMC 构造一条马尔可夫链:当前状态 \(x\) 由提议分布生成新候选 \(x'\),按接受率 \(\alpha\) 决定是否转移。链收敛后,访问各状态的频率分布就是目标分布 \(p(x)\)。与前面方法最大的不同是:样本不再独立,前后状态由链连接。只要转移核满足细致平衡条件,平稳分布就是 \(p\)。Metropolis-Hastings 是其中最经典的算法,对称提议(如高斯游走)下,接受率简化为目标密度的比值。
使用 MCMC 有两个实操要点:一是丢弃“预烧期”(burn-in)——链条刚起步还在爬坡,还没进入平稳分布,开头那几千个样本不能用;二是相邻样本高度相关,通常隔几步取一个(thinning)来降低相关性,否则有效样本量远小于表面数量。
主厨终于明白,高维世界没有捷径:与其全局乱抓(拒绝采样失效),不如局部随机游走,让链自己在配方山上“上坡容易、下坡愿试”。MCMC 因此成为贝叶斯推断、概率编程、强化学习里最有分量的采样工具。
- 提议新点\(x' \sim \mathcal{N}(x, \sigma^2)\) 表示在当前位置附近随机走一步,这是“逛厨房”的步伐
- 密度比值\(\dfrac{f(x')}{f(x)}\) 衡量新货架相对当前货架的“配方味浓度”
- 接受裁剪\(\min(1, r)\) 保证接受概率不超过 1——新点更“高”必接受,更“低”则概率性接受
- 对称性提醒该式仅在提议分布对称时成立;不对称时要补上提议概率比值
AI 应用场景
贝叶斯模型的后验推断
阶段:模型训练 / 不确定性量化
解决的问题:贝叶斯模型的参数后验分布 \(\Pr(\theta \mid D)\) 几乎都没有解析解,传统做法只能最大似然点估计、丢掉不确定性。用 MCMC 把后验当作目标分布进行随机游走采样,就能得到参数的完整分布,而非一个孤点。
具体案例:电商点击率预测的贝叶斯逻辑回归中,用 NUTS(MCMC 的现代变体)从后验抽取 2000 组参数样本,每组样本都是一次“对真实参数的合理猜测”;对 2000 个样本取 2.5% 和 97.5% 分位数,就得到可信区间。广告主由此知道“涨幅最有可能在 3%~7% 之间”,而不是一个虚假的精确数。
强化学习的离线策略评估
阶段:训练 / 策略评估
解决的问题:用旧策略(行为策略)收集的交互数据来评估新策略,两份数据的分布不同,直接平均回报会产生偏差。重要性采样给每条轨迹乘以新旧策略概率比 \(\pi_{\text{new}}/\pi_{\text{old}}\) 作为权重,即可无偏估计新策略的期望回报。
具体案例:自动驾驶仿真器中,用上一版决策策略跑了 100 万帧数据,评估新版策略时不可能全部重跑。工程师按新旧策略的动作概率比给每条轨迹加权,几分钟内估算出新策略的碰撞率与平均油耗,决定要不要上线。
机器人定位中的粒子滤波
阶段:感知 / 状态估计
解决的问题:机器人在未知环境中要知道“我在哪”,后验分布是多峰的、非高斯的,普通滤波无法表达。粒子滤波本质是“重要性采样 + 重采样”的在线组合:用粒子代表位置假设,按观测似然加权、重采样,粒子分布逐渐收敛到真实位置。
具体案例:扫地机器人在客厅与走廊间移动,里程计有漂移,激光观测有噪声。粒子滤波维护 5000 个位置粒子,每次激光扫描后按匹配度更新权重,再按权重重采样,最终粒子聚成几团——机器人据此判断“90% 概率在客厅东北角”。
Python 演示
"""采样方法演示: 逆变换, 拒绝采样, 重要性采样"""import numpy as np def inverse_transform_exp(n_samples, lam=1.0): """逆变换采样: 用 U(0,1) 生成指数分布样本""" u = np.random.uniform(0, 1, n_samples) return -np.log(1 - u) / lam def rejection_beta(n_samples, a=2.0, b=2.0): """拒绝采样: 用 U(0,1) 提案生成 Beta(2,2) 样本""" m = 1.5 # Beta(2,2) 密度最大值, 保证包络罩住 samples = [] n_total = 0 while len(samples) < n_samples: x = np.random.uniform(0, 1) u = np.random.uniform(0, 1) n_total += 1 pdf = 6 * x * (1 - x) # 6 = 1 / B(2,2) if u <= pdf / m: samples.append(x) return np.array(samples), n_total def importance_tail(n_samples=200000): """重要性采样: 估计 N(0,1) 尾部概率 P(X > 2)""" from math import exp, pi, sqrt def p_pdf(x): return exp(-0.5 * x * x) / sqrt(2 * pi) def q_pdf(x): return exp(-0.5 * (x - 2) * (x - 2)) / sqrt(2 * pi) xs = np.random.normal(2, 1, n_samples) weights = np.array([p_pdf(x) / q_pdf(x) for x in xs]) return float(np.mean(weights * (xs > 2))) if __name__ == "__main__": xs = inverse_transform_exp(100000, lam=0.5) print("指数分布样本均值 =", round(xs.mean(), 4), "理论值 =", 2.0) beta_samples, n_total = rejection_beta(10000) print("拒绝采样接受率 =", round(10000 / n_total * 100, 1), "%") print("Beta(2,2) 样本均值 =", round(beta_samples.mean(), 4), "理论值 =", 0.5) est = importance_tail() print("P(X > 2) 估计值 =", round(est, 4), "理论值 =", 0.0228)
u = np.random.uniform(0, 1, n_samples)生成主厨的“幸运百分比”,这是所有采样的原料来源return -np.log(1 - u) / lam指数分布 \(F\) 的反函数,闭眼抽数直接变样本m = 1.5包络常数,Beta(2,2) 的密度最大值,保证 \(Mg \ge f\) 永远成立pdf = 6 * x * (1 - x)计算目标密度值,6 来自贝塔函数 \(1/B(2,2)\)if u <= pdf / m:质检判决:随机点落在曲线下方才接受weights = np.array([p_pdf(x) / q_pdf(x) for x in xs])给每个样本配权重 \(p/q\),把仓库口味修成配方口味return float(np.mean(weights * (xs > 2)))加权平均,估计稀罕的尾部概率
常见误区
误区只要有概率密度函数 PDF,就能用逆变换采样,直接算 \(F^{-1}\) 就行。
正解逆变换采样需要累积分布函数 \(F\) 的反函数可以解析或数值求出。正态分布的 \(F\) 就没有解析反函数,只能用数值方法(如插值求根)勉强反查,效率低且易引入误差。此时拒绝采样或 MCMC 反而更合适。“有 PDF”远不等于“能逆变换”。
为何常见:教材上的例子全是指数、均匀这类反函数好求的分布,看多了容易以偏概全,以为天下分布都能一图反查。
误区接受率是 \(1/M\),那把 \(M\) 设小一点,接受率就高,效率不就上来了?
正解\(M\) 必须满足 \(M \cdot g(x) \ge f(x)\) 对所有 \(x\) 成立,即包络曲线必须完全罩住目标密度。如果 \(M\) 太小导致包络缺口,某些区域的样本永远不会被接受,采出的分布形状就错了——不是效率问题,是正确性问题。先保证罩得住,再谈效率。
为何常见:人的直觉总是先优化“看得见的数字”(接受率),却忽略了“罩不住就会系统性出错”这个隐性前提。
误区重要性采样名字里有“重要性”,那应该是重要的区域多采样、不重要的少采样。
正解重要性采样的样本仍然全部来自提议分布 \(q\),采样策略本身没变。它的巧妙之处在事后加权:每个样本乘以权重 \(p(x)/q(x)\) 修正偏差,让加权后的均值趋近目标期望。如果 \(q\) 选得贴近 \(p\),权重都接近 1,方差就小;选得差,个别权重巨大,估计被“绑架”。
为何常见:望文生义。“重要性”指的是“权重的重要性”,不是“采样密度的重要性”。
误区MCMC 跑完以后得到的样本,跟抽签一样都是独立同分布的。
正解MCMC 的样本是一条马尔可夫链上的连续状态,前后之间高度相关——相邻两步往往靠得很近。所以要用 burn-in 丢弃预烧期,用 thinning 每隔几步取一个样本,才能近似独立。直接拿全部连续样本当独立样本用,会严重低估估计的方差。
为何常见:把“链收敛后分布正确”误当成“每次抽取相互独立”,忽略了链本身的依赖结构。这也是新手诊断 MCMC 输出时最容易翻车的地方。
面试题
Q1. 逆变换采样中,\(X = F^{-1}(U)\) 里的 \(U\) 服从什么分布?
- A.正态分布 N(0,1)
- B.均匀分布 U(0,1)← 正确答案
- C.指数分布 Exp(λ)
- D.泊松分布 Poi(λ)
答案:B。逆变换采样的起点是标准随机数发生器,它只产生 0 到 1 的均匀随机数。\(U\) 必须是均匀分布 \(U(0,1)\),经过 \(F^{-1}\) 映射后才变成目标分布的样本。如果把 \(U\) 换成正态或指数,映射关系就被破坏了。
Q2. 拒绝采样中,包络常数 M 必须满足什么条件?
- A.M 小于目标密度最大值
- B.M 等于提议分布方差
- C.M 要罩住整个目标密度← 正确答案
- D.M 大于所有样本数量
答案:C。\(M \cdot g(x) \ge f(x)\) 必须对所有 \(x\) 成立,包络曲线要完全罩住目标密度曲线。否则漏掉的区域永远采不到样本,分布形状系统性偏差。M 与样本数量、提议分布方差无关,也不该小于密度最大值。
Q3. 重要性采样估计期望时,样本权重应该怎么计算?
- A.目标密度除以提议密度← 正确答案
- B.提议密度除以目标密度
- C.目标密度乘以提议密度
- D.提议密度取对数即可
答案:A。权重 \(w(x) = p(x)/q(x)\),目标密度作分子、提议密度作分母。这是积分恒等变形 \(\int h\,p\,dx = \int h\,(p/q)\,q\,dx\) 的必然结果。方向写反就变成对错误分布的估计,偏差无法消除。
Q4. 下列哪些采样方法必须事先指定一个提议分布?
- A.逆变换采样方法
- B.拒绝采样方法← 正确答案
- C.重要性采样方法← 正确答案
- D.分层采样方法
答案:BC。拒绝采样和重要性采样都从提议分布 \(g\) 或 \(q\) 中抽取候选样本。逆变换采样只依赖均匀分布和目标分布的 CDF 反函数;分层采样只依赖层的划分,不需要额外提议分布。
Q5. 分层采样为什么能降低估计方差?
- A.层内尽量均匀一致← 正确答案
- B.层内样本数完全相等
- C.层与层之间完全相同
- D.每层都用逆变换采样
答案:A。总方差 = 层内方差 + 层间方差。分层把层间差异确定化处理,随机误差只剩层内波动;层内越均匀,层内方差越小,总方差越小。层样本数相等、层间相同都不是降方差的关键。
Q6. MCMC 中丢弃预烧期样本的目的是什么?
- A.减少样本间的相关性
- B.让链到达平稳分布← 正确答案
- C.提高提案的接受概率
- D.缩短随机游走的步长
答案:B。链条从任意初始点出发,需要走一段时间才能收敛到目标分布,这段“爬坡期”就是预烧期。预烧样本并非来自目标分布,必须丢弃。预烧与相关性是两回事,也不影响接受率与步长。
Q7. 对称提议下 Metropolis-Hastings 接受率 \(\alpha=\min(1, f(x')/f(x))\),下列说法正确的有?
- A.新点概率更高就必定接受← 正确答案
- B.新点概率更低就必定拒绝
- C.概率更低的点也有概率被接受← 正确答案
- D.接受率与提议分布完全无关
答案:AC。当 \(f(x') \ge f(x)\) 时比值大于 1,\(\min\) 截断为 1,必定接受;当新点概率更低时,以比值 \(\alpha\) 的概率接受、以 \(1-\alpha\) 拒绝——这正是 MCMC 能探索低概率区域、避免困在局部高峰的原因。接受率虽不含 \(q\),但那是对称提议化简的结果,非对称时仍要补 \(q\) 比值。
Q8. 逆变换采样要求目标分布满足什么条件?
- A.CDF 反函数要容易得到← 正确答案
- B.PDF 必须是对称的
- C.均值必须为零
- D.分布必须来自正态族
答案:A。逆变换采样的数学核心是 \(F^{-1}(U)\),所以 \(F\) 必须可求反函数。分布的对称性、均值、是否正态都不影响这种方法,只要能算出反函数,一切分布皆可。
Q9. 高维空间中拒绝采样效率急剧下降的主要原因是什么?
- A.计算复杂度随维度爆炸
- B.接受率随维度指数衰减← 正确答案
- C.提议分布无法生成样本
- D.目标密度无法解析表达
答案:B。接受率近似等于 \(1/M\),而高维下包络常数 \(M\) 随维度指数增长(提议分布与目标分布的重叠体积急剧缩小),接受率呈指数坍塌。计算复杂度增长是次要问题,本质是“拒绝”这种全局方式在体积上不可持续。
Q10. 关于各种采样方法,以下说法正确的有?
- A.逆变换采样不需要拒绝任何样本← 正确答案
- B.重要性采样可估计目标分布期望← 正确答案
- C.分层采样层间差异越大效果越好← 正确答案
- D.MCMC 样本相互之间完全独立
答案:ABC。逆变换是一一映射,每个均匀数都变成一个样本,零浪费;重要性采样通过加权即可估计期望;分层把层间差异排除出随机误差,层间差异越大收益越明显。MCMC 样本是链上连续状态,前后高度相关,并非独立,需要预烧与间隔抽样处理。