Python 3.x landau pdf上的拒绝方法

Python 3.x landau pdf上的拒绝方法,python-3.x,random,Python 3.x,Random,我一直在尝试使用拒绝-接受算法为landau PDF创建一个随机数生成器。问题是编译似乎需要很长时间,生成的值似乎不符合PDF格式。 这是我尝试使用的代码: import matplotlib.pyplot as plt import numpy as np import time from sympy import sqrt,exp,pi a=0 # xmin b=150 # xmax h=0.25 # ymax variables = [] #list for variables

我一直在尝试使用拒绝-接受算法为landau PDF创建一个随机数生成器。问题是编译似乎需要很长时间,生成的值似乎不符合PDF格式。 这是我尝试使用的代码:

import matplotlib.pyplot as plt
import numpy  as np
import time
from sympy import sqrt,exp,pi

a=0   # xmin
b=150 # xmax

h=0.25 # ymax
variables = [] #list for variables
def f(x):
    return 1/(sqrt(2*pi))*exp(-1/2*((x-25)+exp(-(x-25))))  #probability density function


reject = 0   # number of rejections
start = time.time()
while len(variables) < 100000:  #I want to generate 100 000 variables
    u1 = random.uniform(a,b)
    u2 = random.uniform(0,h)

    if u2 <= f(u1):
        variables.append(u1)
    else:
        reject +=1
end = time.time()

print("Time: ", end-start)
print("Rejection: ", reject)
xx = np.linspace(a,b,150)

plt.hist(variables,50, density=1)
plt.show()
导入matplotlib.pyplot作为plt
将numpy作为np导入
导入时间
从sympy导入sqrt、exp、pi
a=0#xmin
b=150#xmax
h=0.25#ymax
变量=[]#变量列表
def f(x):
返回1/(sqrt(2*pi))*exp(-1/2*((x-25)+exp(-(x-25)))#概率密度函数
拒绝=0#拒绝次数
开始=时间。时间()
而len(variables)<100000:#我想生成100000个变量
u1=随机均匀(a,b)
u2=随机均匀(0,h)

如果u2为什么会出现问题???拒绝方法总是存在性能问题,如果您将其与Symphy结合使用。。。。这不是个好主意。我建议您将上面脚本的第一块替换为:

import matplotlib.pyplot as plt
import numpy  as np
import time
import random
from scipy import sqrt,exp,pi
然后,它至少运行(一些您可以轻松修复的警告)并生成正确的输出:

Time:  61.50497007369995
Rejection:  3671570

为什么速度慢?

因为你用概率
1-f(u1)/0.25丢弃随机值,这个概率仅在
u1~25的分布峰值附近很小。它实际上在你到达之前就变成了数值
1.0
,因为
f2(150)=12.8675100380087668e-28
!这意味着您放弃100%的随机数尝试,以获得更大的
u1
,这是非常低效的

提高代码速度的一个好方法是缩小
u1
的范围。只要更改
b=50
,您就可以得到:

Time:  20.477684020996094
Rejection:  1145527
-->三倍的速度和相同的结果

就这些吗?

不,如果你真的很在意速度,你不应该总是在0到0.25的间隔上产生
u2
。您可以使用任何上界,只要它保持小于实际朗道分布。它必须是一个“信封”。这可能会大大增加计算时间,因为您降低了拒绝概率。然而,对于蓝鹰来说,这并不简单,因为它的尾巴很长。但您可以肯定地发现,至少在
u1
的特定范围内

我刚才测试的一个相当愚蠢的方法是将问题分成四个区间[A,b)=[0,27],[27,30],[30,35],[35,50],u2的上限为0.25,0.11,0.05,0.01,并获得另一个几乎2加速系数:

Time:  12.69986867904663
Rejection:  661561
当然,同样的,统计上相同的结果:

通过一些工作,您可以得到比这更好的结果。编辑的原理代码示例示例是(这可以做得更好/更好):

与我的初始版本相比,这是性能改进的3892倍,我确信与sympy相比,这甚至远不止于此。了解我们编码的内容、原因和方式非常重要


事实上,我很感兴趣:是否有人可以进一步改进此最新版本的代码?

为什么是Symphy???如果将此与Symphy结合使用,拒绝方法总是存在性能问题……这不是一个好主意。我建议您将上面脚本的第一部分替换为:

import matplotlib.pyplot as plt
import numpy  as np
import time
import random
from scipy import sqrt,exp,pi
然后,它至少运行(一些您可以轻松修复的警告)并生成正确的输出:

Time:  61.50497007369995
Rejection:  3671570

为什么速度慢?

因为你用概率
1-f(u1)/0.25丢弃随机值,这个概率仅在
u1~25
的分布峰值附近很小。它实际上在你到达
u1=150
之前就变成了数值
1.0
,因为
f2(150)=12.8675100380087668e-28
!这意味着您放弃100%的随机数尝试,以获得更大的
u1
,这是非常低效的

加快代码速度的一个好方法是缩小
u1
的范围。只需更改
b=50
,您就可以得到:

Time:  20.477684020996094
Rejection:  1145527
-->三倍的速度和相同的结果

就这些吗?

不,如果你真的关心速度,你不应该总是在0到0.25的间隔上产生
u2
。你可以使用任何上界,只要它小于实际的朗道分布。它必须是一个“信封”。这可能会大大增加计算时间,因为您会降低拒绝概率。对于Landau来说,这并不简单,因为它的尾部很长。但您肯定会在
u1
的特定范围内找到某些东西

我刚才测试的一个相当愚蠢的方法是将问题分成四个区间[A,b)=[0,27],[27,30],[30,35],[35,50],u2的上限为0.25,0.11,0.05,0.01,并获得另一个几乎2加速系数:

Time:  12.69986867904663
Rejection:  661561
当然,同样的,统计上相同的结果:

通过一些工作,您可以得到比这更好的结果。编辑的原理代码示例示例是(这可以做得更好/更好):

与我的初始版本相比,这是性能改进的3892倍,我确信与sympy相比,这甚至远不止于此。了解我们编码的内容、原因和方式非常重要


事实上,我很感兴趣:是否有人可以进一步改进此最新版本的代码?

已编辑,请再次检查。现在重新编辑,请检查!请注意
scipy.stats.moyal(25).rvs(100000)
是一个很好的近似值,在我的笔记本电脑上生成100k个样本只需1000万秒。请再次检查。现在重新编辑,请检查!注意
scipy.stats.moyal(25).rvs(100_000)
是一个很好的近似值,在我的笔记本电脑上生成10万个样本只需1千万秒非常感谢!它确实有帮助,但不确定如何将间隔分割成段(请显示代码条)使用numpy import sqrt、exp、pi的
而不是scipy后,速度也加快了)我添加了上面的代码在我的答案中添加了一个版本的代码,它实际上使用了矢量化num