如果说最常用的分布是哪个,第一个当属均匀分布,第二个就非高斯分布莫属了,在机器学习中常见的采样方法中介绍了均匀分布的采样,本文来介绍一下高斯分布的采样.
首先,假设随机变量服从标准正态分布,令:
则服从均值为,方差为的高斯分布.因此,任意高斯分布都可以由标准正态分布通过拉伸和平移得到,所以这里只考虑标准正态分布的采样.
由于高斯分布的累积分布函数并不是一个初等函数,所以使用逆变换法计算比较麻烦,Box-Muller算法给出了简单的解决方案.
Box-Muller算法
假设是两个服从标准正态分布的独立随机变量,他们的联合概率密度为
考虑在圆盘上的概率
通过极坐标变换将转化为,可以很容易求得二重积分:
这里可以看成是极坐标中的累积分布函数.由于的计算公式比较简单,逆函数也容易求得,所以可以利用逆变换法来对进行采样;对于,在上进行均匀采样即可.这样就得到了,经过坐标变换即可得到符合标准正态分布的.具体采样过程如下:
- 产生上的两个独立的均匀分布随机数
- 令,则服从标准正态分布,并且是相互独立的.
Box-muller算法由于需要计算三角函数,相对来说还是比较耗时,而Marsaglia polar method则避开了三角函数的计算,因而更快,其具体采样操作如下:
- 在单位圆盘上产生均匀分布随机数对(在矩阵上利用拒绝采用法即可得到).
- 另,则是两个服从标准正态分布的样本,其中用来代替Box-muller算法中的cos和sin操作.
编程实现
import matplotlib.pyplot as plt
import numpy as np
def getNormal(SampleSize):
iid = np.random.uniform(0,1,SampleSize)
normal1 = np.cos(2*np.pi*iid[0:int(SampleSize/2-1)])*np.sqrt(-2*np.log(iid[int(SampleSize/2):SampleSize-1]))
normal2 = np.sin(2*np.pi*iid[0:int(SampleSize/2-1)])*np.sqrt(-2*np.log(iid[int(SampleSize/2):SampleSize-1]))
return np.hstack((normal1,normal2))
# 生成10000000个数,观察它们的分布情况
SampleSize = 10000000
normal = getNormal(SampleSize)
plt.hist(normal,np.linspace(-4,4,81),facecolor="green")
plt.show()