我的用例是在所有小于10的点上评估Poisson pmf,并且我会多次调用这样的函数,并且使用不同的lambda。 lambda不是提前知道的,所以我无法对lambdas进行矢量化。
我从某个地方听说过使用_pmf
的秘密技巧。这样做的缺点是什么?但是,它有点慢,有没有办法改进它而不从头开始重写C中的pmf?
%timeit scipy.stats.poisson.pmf(np.arange(0,10),3.3)
%timeit scipy.stats.poisson._pmf(np.arange(0,10),3.3)
a = np.arange(0,10)
%timeit scipy.stats.poisson._pmf(a,3.3)
10000 loops, best of 3: 94.5 µs per loop
100000 loops, best of 3: 15.2 µs per loop
100000 loops, best of 3: 13.7 µs per loop
好吧,我只是懒得用cython写的。我原本预计所有离散分布都有一个更快的解决方案,可以按顺序(迭代)对连续x
进行评估。例如。 P(X=3) = P(X=2) * lambda / 3 if X ~ Pois(lambda)
我现在对Scipy和Python的信心不足。库函数不像我预期的那样先进。
答案 0 :(得分:3)
大多数scipy.stats
发行版都支持矢量化评估:
>>> poisson.pmf(1, [5, 6, 7, 8])
array([ 0.03368973, 0.01487251, 0.00638317, 0.0026837 ])
这可能或者可能不够快,但您可以尝试将pmf
次呼叫带出循环。
pmf
和_pmf
之间的区别:真正的工作是在强调的函数(_pmf
,_cdf
等)中完成的,而公共函数({{1} },pmf
)确保只有有效的参数才能使它成为cdf
(如果参数无效,则_pmf
的输出不能保证有意义,因此请自行承担风险)。
_pmf
更多详情:https://github.com/scipy/scipy/blob/master/scipy/stats/_distn_infrastructure.py#L2721
答案 1 :(得分:2)
尝试在cython中实现pmf。如果你的scipy是像Anaconda或Enthought这样的软件包的一部分你可能已经安装了cython。 http://cython.org/
尝试用pypy运行它。 http://pypy.org/
在大型AWS服务器(或类似服务器)上租用时间。
答案 2 :(得分:0)
我发现scipy.stats.poisson
类与简单的python实现相比非常慢。
没有cython,载体或其他任何东西。
import math
def poisson_pmf(x, mu):
return mu**x / math.factorial(x) * math.exp(-mu)
def poisson_cdf(k, mu):
p_total = 0.0
for x in range(k + 1):
p_total += poisson_pmf(x, mu)
return p_total
如果您检查scipy.stats.poisson
中的source code(甚至是带下划线的前缀版本),则很清楚为什么!
上述实现现在比在C语言中(与gcc -O3
v9.3编译时)完全相同,仅慢 10倍。 scipy版本至少要慢10倍。
#include <math.h>
unsigned long factorial(unsigned n) {
unsigned long fact = 1;
for (unsigned k = 2; k <= n; ++k)
fact *= k;
return fact;
}
double poisson_pmf(unsigned x, double mu) {
return pow(mu, x) / factorial(x) * exp(-mu);
}
double poisson_cdf(unsigned k, double mu) {
double p_total = 0.0;
for (unsigned x = 0; x <= k; ++x)
p_total += poisson_pmf(x, mu);
return p_total;
}