3. 概率分布抽样方法
蒙特卡洛仿真的核心动作,是把“不确定性”变成一串可计算的随机数。计算机能直接提供的只有均匀分布随机数 U ~ Uniform(0,1),而仿真中真正需要的是正态分布的服务时间、指数分布的故障间隔、泊松分布的到达人数、伽马分布的累积损伤等。因此,抽样方法的任务就是:把均匀随机数确定性地变换为目标分布的随机数。本节围绕逆变换法、拒绝采样法、Box-Muller 变换三条主线,并给出正态、指数、泊松、伽马四类常见分布的抽样实现要点。
一、逆变换法:用累积分布函数的反函数“搬运”随机性
逆变换法(Inverse Transform Method)适用于累积分布函数 F(x) 可解析求逆的分布。其原理是:若 U ~ Uniform(0,1),令 X = F⁻¹(U),则 X 的分布函数恰为 F。直观理解是:U 在纵轴上均匀落点,经过 F⁻¹ 映射后,落点密集处对应概率密度高的区间。
以指数分布为例,F(x) = 1 - e^(-λx),反解得 X = -ln(1-U)/λ。由于 1-U 与 U 同为均匀分布,工程上常直接写 X = -ln(U)/λ。假设某设备故障间隔服从 λ = 0.02 次/小时的指数分布(均值 50 小时),取 U = 0.35,则 X = -ln(0.35)/0.02 ≈ 52.5 小时。这个计算过程完全可复现,是逆变换法最典型的落地形式。
离散分布同样可用逆变换法,只是把反函数换成“累积概率区间查找”。泊松分布 P(X=k) = e^(-λ)λ^k/k! 没有简单的闭式反函数,实践中采用累积求和加搜索:先计算 p₀ = e^(-λ),再递推 pₖ = pₖ₋₁·λ/k,累加至超过 U 时返回对应的 k。当 λ 较大时,这种线性搜索效率下降,可改用正态近似或接受-拒绝类算法。
# 逆变换法:指数分布抽样(Python 伪代码)
import math, random
def sample_exp(lam):
u = random.random() # U ~ Uniform(0,1)
return -math.log(u) / lam # F⁻¹(U)
# 示例:λ=0.02,抽 5 个故障间隔
for _ in range(5):
print(round(sample_exp(0.02), 2))
二、拒绝采样法:用“易抽分布”包裹“难抽分布”
当目标密度 f(x) 难以直接抽样或求逆时,拒绝采样法(Rejection Sampling)提供了一条通用路径。选一个容易抽样的提议分布 g(x),并找到常数 M 使 f(x) ≤ M·g(x) 对所有 x 成立。每次从 g 抽一个候选值 Y,再抽 U ~ Uniform(0,1),若 U ≤ f(Y)/(M·g(Y)) 则接受 Y,否则拒绝并重抽。
接受率等于 1/M,因此 M 越接近 1 效率越高;M 过大时大量候选被丢弃,计算浪费严重。以用均匀分布 g(x)=1(区间 [0,1])抽取密度 f(x)=2x 为例,取 M=2,接受条件为 U ≤ Y,理论接受率 50%。这说明拒绝采样不是“免费”的,它用计算量换取了实现上的通用性。
1/M。若低于 20%,通常应更换提议分布或改用其他算法,否则单次抽样成本可能高到影响仿真整体性能。三、Box-Muller 变换:两个均匀数生成一对正态数
正态分布没有闭式反函数,逆变换法不直接适用。Box-Muller 变换利用极坐标思想:取两个独立均匀数 U₁、U₂,令 R = √(-2ln U₁),θ = 2πU₂,则 Z₁ = R·cosθ、Z₂ = R·sinθ 是两个独立的标准正态随机数。一次计算产出两个样本,效率较高。
实际实现中要注意 U₁ 不能取 0,否则对数发散;通常用 1-U₁ 或对随机数做开区间保护。若需要 N(μ, σ²),再作线性变换 X = μ + σZ。例如 μ=100、σ=15,得到 Z=-0.8 时,X = 100 + 15×(-0.8) = 88。这一变换保持分布形状不变,只改变位置和尺度。
四、常见分布的抽样实现与选择依据
伽马分布 Gamma(α, β) 的抽样需分情况:当形状参数 α 为整数时,可视为 α 个独立指数分布之和,逐个逆变换后相加即可;当 α 非整数时,常用 Marsaglia-Tsang 方法,结合正态提议与拒绝修正。指数分布是 α=1 的伽马特例,因此指数抽样代码可作为伽马整数情形的构件复用。
选择哪种方法,取决于分布是否可求逆、密度是否已知、对效率的要求。逆变换法简单稳定、便于方差缩减(如分层抽样、对偶变量),应优先考虑;拒绝采样法通用但有效率损耗;Box-Muller 专用于正态且成对产出。下表汇总四类分布的推荐实现路径。
| 分布 | 推荐方法 | 关键公式/条件 | 注意事项 |
|---|---|---|---|
| 指数 Exp(λ) | 逆变换法 | X = -ln(U)/λ | U 取开区间,避免 ln(0) |
| 正态 N(μ,σ²) | Box-Muller | Z = √(-2lnU₁)·cos(2πU₂) | 成对产出,缓存第二个值 |
| 泊松 Poi(λ) | 累积概率搜索 | 累加 pₖ 至超过 U | λ 大时改用正态近似 |
| 伽马 Gamma(α,β) | 整数:指数求和;非整数:Marsaglia-Tsang | α 个 Exp(β) 之和 | 注意形状/尺度参数化差异 |
实现层面还有两个容易踩坑的细节。第一是参数化约定:伽马分布有“形状-尺度”和“形状-率”两种写法,β 是尺度还是率会直接导致结果差一个量级,代码注释中必须写清。第二是随机数质量:逆变换法对均匀随机数的均匀性很敏感,若底层生成器周期短或存在相关性,抽样结果会系统性偏移,建议使用经过检验的生成器并固定随机种子以便复现。
验证抽样是否正确,不必依赖复杂统计检验,先做三件事即可:一是直方图与理论密度对比,观察形状是否吻合;二是检查样本均值与方差是否接近理论值(如指数分布均值 1/λ、方差 1/λ²);三是重复多次抽样,观察统计量是否稳定。若直方图出现截断、堆积或明显偏斜,应优先排查反函数推导、接受条件符号和参数化约定,而不是急于更换算法。