Uniform to Normal

 

🧩 一、核心思想:Transform Uniform → Normal

几乎所有方法都基于以下逻辑:
如果你能生成
那么可以通过某种变换 使得 的分布就是目标分布。
对正态分布 ,有多种实现方式,从理论精确到数值逼近,下面依次介绍。

🧮 方法 1:Inverse Transform Sampling(反变换法)

原理:
如果 ,则
服从标准正态分布。
因为

代码:
import numpy as np import scipy.stats as st U = np.random.rand(10000) Z = st.norm.ppf(U)
  • ppf 是 “percent point function” = CDF 的反函数。
  • 优点:理论上精确;简单。
  • 缺点:需要高精度计算 (\Phi^{-1}),在尾部数值不稳定、计算慢。

应用:
  • Stratified Sampling(分层抽样)里使用的就是它!
    • 因为你知道每层的概率区间 ,所以自然用反变换法取样。

🧮 方法 2:Box–Muller Transform(极坐标法)

原理:
使用两个独立的 ,生成两个独立的
[
\begin{aligned}
Z_1 &= \sqrt{-2\ln U_1} \cos(2\pi U_2), \
Z_2 &= \sqrt{-2\ln U_1} \sin(2\pi U_2).
\end{aligned}
]
推导思路:
  1. 设 ()。
  1. 令 (),
    1. 即在极坐标下生成等价分布点。

代码:
U1, U2 = np.random.rand(10000), np.random.rand(10000) Z1 = np.sqrt(-2 * np.log(U1)) * np.cos(2 * np.pi * U2) Z2 = np.sqrt(-2 * np.log(U1)) * np.sin(2 * np.pi * U2)
特点:
  • 精确、解析。
  • ppf 法快得多(不需数值求反函数)。
  • 常用于模拟系统底层(例如 C 库里的 randn() 就是变体)。

🧮 方法 3:Marsaglia Polar Method(Box–Muller 改进)

思想:
去掉三角函数,避免调用 sin / cos
算法:
  1. 生成 (U_1, U_2 \sim \text{Uniform}(-1,1)),
    1. 计算 (S = U_1^2 + U_2^2)。
  1. 若 (S \ge 1) 则重新生成。
  1. 否则令:
    1. [
      Z_1 = U_1 \sqrt{\frac{-2\ln S}{S}}, \quad
      Z_2 = U_2 \sqrt{\frac{-2\ln S}{S}}.
      ]
代码:
def marsaglia_normal(n=10000): Z = [] while len(Z) < n: U1, U2 = np.random.uniform(-1, 1, 2) S = U1**2 + U2**2 if S >= 1 or S == 0: continue factor = np.sqrt(-2 * np.log(S) / S) Z += [U1 * factor, U2 * factor] return np.array(Z[:n])
优点:
  • 无三角函数,更高效;
  • 广泛用于底层库(NumPy、C++ STL、GPU kernels)。

🧮 方法 4:Ziggurat Algorithm(采样分块法)

思想:
把正态密度函数下的区域分为许多矩形层(ziggurats,像阶梯塔)。
随机挑选层和层内点,通过拒绝采样得到正态样本。
特点:
  • 极高性能(工业级库,如 NumPy np.random.randn()、Intel MKL 都使用);
  • 理论上属于 accept–reject sampling
  • 细节较复杂,一般不手写。

伪代码概念图:
f(z) │ ___ │ | |______ │ | | |____ │ | | | |__ │ | | | | | └────────────────────────────── z
随机:
  • 选层号;
  • 在矩形内均匀取样;
  • 若点在密度曲线下 → 接受,否则重采样。

🧮 方法 5:CLT Approximation(中心极限定理法)

思想:
如果生成 (U_i \sim [0,1]),则
[
Z = \sqrt{12} \left(\frac{1}{12}\sum_{i=1}^{12} U_i - \frac{1}{2}\right)
]
近似服从 (N(0,1))。
原因:
(\sum U_i) 的分布趋近正态(中心极限定理)。
代码:
U = np.random.rand(12, 10000) Z = np.sqrt(12) * (np.mean(U, axis=0) - 0.5)
特点:
  • 概念简单;
  • 但精度差(尾部不准确,分布较扁)。

✅ 总结对比表

方法
数学原理
精度
速度
是否常用
Inverse CDF (PPF)
反变换法
⭐⭐⭐⭐
理论上最精确(用于分层采样)
Box–Muller
极坐标法
⭐⭐⭐⭐
⭐⭐⭐
常见教学与底层实现
Marsaglia Polar
改进Box–Muller
⭐⭐⭐⭐
⭐⭐⭐⭐
实用高效(NumPy底层)
Ziggurat
分层拒绝采样
⭐⭐⭐⭐
⭐⭐⭐⭐⭐
工业级最快算法
CLT Approx.
中心极限定理
⭐⭐
⭐⭐⭐
简单但粗糙

📊 可视化小示例

import matplotlib.pyplot as plt Z_ppf = st.norm.ppf(np.random.rand(10000)) Z_box = np.sqrt(-2*np.log(np.random.rand(10000))) * np.cos(2*np.pi*np.random.rand(10000)) Z_clt = np.sqrt(12)*(np.mean(np.random.rand(12,10000),axis=0)-0.5) plt.hist(Z_ppf, bins=40, density=True, alpha=0.6, label="PPF") plt.hist(Z_box, bins=40, density=True, alpha=0.5, label="Box-Muller") plt.hist(Z_clt, bins=40, density=True, alpha=0.4, label="CLT Approx") x = np.linspace(-4,4,400) plt.plot(x, st.norm.pdf(x), 'k-', lw=2, label='True N(0,1)') plt.legend() plt.title("Different methods for sampling Normal from Uniform(0,1)") plt.show()

是否希望我帮你可视化 Ziggurat 与 Box–Muller 的几何原理图(展示采样点是如何被“映射”到正态分布上的)?
那样可以直观看到为什么这两种算法等价于从二维均匀点“拉伸”到正态形状。