最近在学习基于蒙特卡罗的强化学习方法时遇到 生成服从正态分布的随机数的算法,因此做一个回顾和总结。
要编程得到服从均匀分布的伪随机数是容易的,C、Python、Java语言等都提供了相应的函数。
但是要想生成服从正态分布的随机数就没那么容易了,生成服从正态分布的随机数的基本思想是先得到服从均匀分布的随机数,再将服从均匀分布的随机数转变为服从正态分布。
实现均匀分布到正态分布转变的方法:
- 利用分布函数的反函数
使用反函数,先随机抽出一个服从[0,1]均匀分布的数字u,然后
那z是正态分布的
import numpy as np
from scipy.special import erfinv
def inverfsampling(mu=0, sigma=1, size=1):
z = np.sqrt(2) * erfinv(2 * np.random.uniform(size=size) - 1)
return mu + z * sigma
- Box Muller方法
则 和均服从正态分布。
import numpy as np
def boxmullersampling(mu=0, sigma=1, size=1):
u = np.random.uniform(size=size)
v = np.random.uniform(size=size)
z = np.sqrt(-2 * np.log(u)) * np.cos(2 * np.pi * v)
return mu + z * sigma
- 利用中心极限定理
中心极限定理告诉我们,当样本量足够大时,样本均值的分布慢慢变成正态分布。
import numpy as np
import matplotlib.pylab as plb
from scipy import stats
import math
number=[30,100,300,1000,5000,30000]
y=[]
for i in range(len(number)):
ave_uniform=[]
for j in range(1000):
data=np.random.uniform(-1,1,number[i])
variance=(1.0/3.0)/(1.0*number[i])
summer=sum(data)
ave_uniform.append(summer/(1.0*number[i]))
Range=np.arange(-0.5,0.5,0.001)
plb.subplot(230+i+1)
plb.plot(Range,stats.norm.pdf(Range,0,math.sqrt(variance)))
plb.hist(ave_uniform,bins=100)
plb.show()
关于正态分布的理论证明,可参考课程:http://open.163.com/movie/2011/6/G/I/M82IC6GQU_M83JBFVGI.html