迭代调用stats.norm.pdf()运行缓慢

时间:2018-05-15 00:34:21

标签: python performance loops scipy

我注意到下面的代码需要0.01秒,因为我需要它运行大约一百万次。

mydist = stats.norm(mean, 2)
for x in range(5,30):               
     probplak.append(mydist.pdf(x))

是否有其他方法可以得到类似的结果(一个值列表给出平均值和x值远离给出标准偏差的平均值?)。

1 个答案:

答案 0 :(得分:4)

mydist.pdf可以传递一系列值而不是单个标量:

probplak = mydist.pdf(range(5, 30))

这比使用for循环更快地产生结果。

例如,

import scipy.stats as stats
mean = 15
mydist = stats.norm(mean, 2)
probplak = mydist.pdf(range(5, 30))
# array([7.43359757e-07, 7.99187055e-06, 6.69151129e-05, 4.36341348e-04,
#        2.21592421e-03, 8.76415025e-03, 2.69954833e-02, 6.47587978e-02,
#        1.20985362e-01, 1.76032663e-01, 1.99471140e-01, 1.76032663e-01,
#        1.20985362e-01, 6.47587978e-02, 2.69954833e-02, 8.76415025e-03,
#        2.21592421e-03, 4.36341348e-04, 6.69151129e-05, 7.99187055e-06,
#        7.43359757e-07, 5.38488002e-08, 3.03794142e-09, 1.33477831e-10,
#        4.56736020e-12])

使用IPython执行速度比较:

In [112]: %timeit mydist.pdf(range(5, 30))              # <-- passing sequence
10000 loops, best of 3: 134 µs per loop

In [113]: %timeit [mydist.pdf(x) for x in range(5,30)]  # <-- using a loop
100 loops, best of 3: 2.95 ms per loop

另请注意,stats.norm.pdf不仅可以为x传递类似数组的参数,还可以传递loc(即mean)和scale(即标准偏差)。 这意味着如果你需要运行这个代码一百万 不同的手段和尺度,然后你可以计算 只需拨打一次probplak,就可以同时查看所有stats.norm.pdf

means = [1,2,3]
std_devs = [10,20,30]
probplaks = stats.norm.pdf(np.arange(5, 30)[:,None], means, std_devs)

返回形状(25, 3)的数组。如果您将meansstd_devs更改为包含一百万个值的列表,则probplaks.shape将为(25, 10**6)

通过一次调用stats.norm.pdf计算所有probplaks将比Python循环中对mydist.pdf的一百万次调用快得多:

In [117]: %timeit stats.norm.pdf(np.arange(5, 30)[:,None], means, scales)
10000 loops, best of 3: 135 µs per loop

In [118]: %timeit [[stats.norm(m, s).pdf(x) for x in range(5,30)] for m,s in zip(means,scales)]
10 loops, best of 3: 64.4 ms per loop