正态分布随机数生成算法

最近在学习基于蒙特卡罗的强化学习方法时遇到 生成服从正态分布的随机数的算法,因此做一个回顾和总结。

要编程得到服从均匀分布的伪随机数是容易的,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方法
Box Muller方法的推导过程较为复杂。但得到的结果却是很令人满意的。只要用两个相互独立的均匀分布就能得到正态分布用Box-Muller方法,随机抽出两个从均[0,1]匀分布的数字u和v。然后




均服从正态分布。


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  
  

  • 利用中心极限定理
利用林德伯格-莱维(Lindeberg—Levi)中心极限定理, 独立同分布的事件,具有相同的期望和方差,则事件服从中心极限定理。他表示了对于抽取样本,n足够大的时候,样本分布符合x~N(μ,σ^2)。
中心极限定理告诉我们,当样本量足够大时,样本均值的分布慢慢变成正态分布。
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

猜你喜欢

转载自blog.csdn.net/u010899985/article/details/80784810