什么是Box-Muller变换?
Box-Muller变换是一种数学方法,可以从0到1的均匀分布中生成标准正态分布(也就是平均值为0,标准差为1的正态分布)的数据。
Box-Muller变换的基本思想是首先生成两个独立且分布均匀的随机变量,然后通过一定的数学变换,将这两个随机变量转换成两个独立的标准正态分布的随机变量。
这样做的好处是,生成均匀分布的随机变量比较容易且直观,然后通过Box-Muller变换,我们可以得到我们需要的正态分布的随机变量。
具体的变换步骤:
假设U1和U2是两个独立的、在(0,1)上均匀分布的随机数,则可通过如下公式生成两个独立的、服从标准正态分布的随机数:
Z0 = sqrt(-2.0 * log(U1)) * cos(2*pi*U2)
Z1 = sqrt(-2.0 * log(U1)) * sin(2*pi*U2)
在这里,log是自然对数,sqrt是平方根,cos是余弦函数,sin是正弦函数,pi是圆周率,这都是数学里常用的函数和常量。使用这两个公式,就可以从U1和U2生成我们需要的正态分布的随机数Z0和Z1。
Box-Muller变换前后比较
使用pycharm运行以下python代码
import numpy as np
import matplotlib.pyplot as plt
import time
class RandNum:
def __init__(self):
self.seed = int(time.time())
def uniform(self, num):
np.random.seed(self.seed)
self.seed += 1
return np.random.uniform(0, 1, num)
def normal(self, num):
u1 = self.uniform(num)
u2 = self.uniform(num)
z0 = np.sqrt(-2 * np.log(u1)) * np.sin(2.0 * np.pi * u2)
z1 = np.sqrt(-2 * np.log(u1)) * np.cos(2.0 * np.pi * u2)
return u1, u2, z0, z1
# 主程序
if __name__ == "__main__":
randnum = RandNum()
u1, u2, z0, z1 = randnum.normal(10000)
plt.figure(figsize=(10, 10))
# 绘制u1的直方图
plt.subplot(221)
plt.hist(u1, bins=30, density=True, alpha=0.5, color='steelblue', edgecolor='none')
plt.title("Histogram of u1")
# 绘制u2的直方图
plt.subplot(222)
plt.hist(u2, bins=30, density=True, alpha=0.5, color='green', edgecolor='none')
plt.title("Histogram of u2")
# 绘制z0的直方图
plt.subplot(223)
plt.hist(z0, bins=30, density=True, alpha=0.5, color='red', edgecolor='none')
plt.title("Histogram of z0")
# 绘制z1的直方图
plt.subplot(224)
plt.hist(z1, bins=30, density=True, alpha=0.5, color='yellow', edgecolor='none')
plt.title("Histogram of z1")
plt.show()