
本文介绍几种主流的非均匀随机数生成方法,包括逆变换采样、拒绝采样和重要性采样,重点说明其原理、适用条件与实现要点,并提供 python 示例代码。
本文介绍几种主流的非均匀随机数生成方法,包括逆变换采样、拒绝采样和重要性采样,重点说明其原理、适用条件与实现要点,并提供 python 示例代码。
在科学计算、蒙特卡洛模拟和机器学习中,常需从自定义概率密度函数(PDF)$ f(x) $ 中高效采样——即生成服从该分布的随机数序列。这并非简单调用 random() 即可解决,而需借助非均匀随机变元生成(Non-uniform Random Variate Generation) 的系统方法。核心挑战在于:均匀随机数源(如 numpy.random.uniform)仅能直接生成 $ \text{Uniform}(0,1) $,必须通过数学变换或筛选策略将其“映射”至目标分布。
以下是三种最常用且原理清晰的方法:
1. 逆变换采样(Inverse Transform Sampling)
适用前提:目标分布的累积分布函数(CDF)$ F(x) = \int_{-\infty}^{x} f(t)\,dt $ 存在解析表达式,且其反函数 $ F^{-1}(u) $ 可高效计算。
原理:若 $ U \sim \text{Uniform}(0,1) $,则 $ X = F^{-1}(U) $ 满足 $ X \sim f(x) $。
示例(指数分布):
import numpy as np
def sample_exp(lam=1.0, size=1000):
u = np.random.uniform(0, 1, size)
return -np.log(1 - u) / lam # F⁻¹(u) = -ln(1-u)/λ
# 验证:直方图近似指数密度曲线
import matplotlib.pyplot as plt
samples = sample_exp(size=10000)
plt.hist(samples, bins=50, density=True, alpha=0.7)
x = np.linspace(0, 10, 100)
plt.plot(x, lam * np.exp(-lam * x), 'r-', lw=2)
plt.show()
2. 拒绝采样(Rejection Sampling)
适用前提:存在一个易采样的“建议分布” $ g(x) $(如均匀或正态),满足 $ f(x) \leq M \cdot g(x) $ 对所有 $ x $ 成立,其中 $ M > 0 $ 为常数。
原理:重复执行:① 从 $ g(x) $ 采样 $ x' $;② 从 $ \text{Uniform}(0,1) $ 采样 $ u $;③ 若 $ u \leq f(x') / (M g(x')) $,接受 $ x' $,否则拒绝。
注意:接受率 $ = 1/M $,故应尽量使 $ M $ 接近最小上界以提升效率;若 $ f(x) $ 无界(如原问题所述),需先截断或重参数化,否则 $ M \to \infty $ 导致算法失效。
3. 其他实用方案
- 分位数函数近似:当 $ F^{-1} $ 无解析解时,可用数值方法(如 scipy.stats.rv_continuous 自定义分布并调用 .rvs())。
- Metropolis-Hastings 等 MCMC 方法:适用于高维、复杂后验分布,但需处理收敛性与相关性。
- 查表法(Alias Method / Ziggurat):针对离散分布或预计算密度网格,兼顾速度与精度。
关键提醒:
✅ 务必确保 $ f(x) \geq 0 $ 且已归一化($ \int f(x)\,dx = 1 $);
⚠️ 原问题中“若 f(a) 1 $ 时接受概率超限,导致逻辑错误;
? 实际工程中,优先使用成熟库(如 scipy.stats、torch.distributions)而非手写采样器,以保障数值稳定性与性能。
掌握这些方法,即可系统性地将任意可计算的 PDF 转化为真实可用的随机样本流。










