我试图在用Cython,在很大程度上依赖于像一些numpy的/ SciPy的数学函数计算numpy.log
。 我注意到,如果我在用Cython一个循环反复调用numpy的/ SciPy的功能外,还有巨大的间接成本,如:
import numpy as np
cimport numpy as np
np.import_array()
cimport cython
def myloop(int num_elts):
cdef double value = 0
for n in xrange(num_elts):
# call numpy function
value = np.log(2)
这是非常昂贵的,大概是因为np.log
经过Python的,而不是直接调用numpy的C函数。 如果我更换符合:
from libc.math cimport log
...
# calling libc function 'log'
value = log(2)
那么它的速度更快。 然而,当我试图通过一个numpy的阵列到libc.math.log:
cdef np.ndarray[long, ndim=1] foo = np.array([1, 2, 3])
log(foo)
它给出了这样的错误:
TypeError: only length-1 arrays can be converted to Python scalars
我的问题是:
- 是否可以调用C函数,并将它传递一个numpy的阵列? 或者,可以只对标量值使用,这要求我写一个循环(例如,如果我想将它应用到
foo
上述阵列。) - 有没有类似的方法来调用由C SciPy的功能的情况下直接Python的开销? 这我怎么能导入SciPy的的C函数库?
具体的例子:假设你要调用许多SciPy的公司或numpy的非常有用的统计功能(如scipy.stats.*
上标量值内) for
在用Cython循环? 这太疯狂了重新实现在用Cython所有这些功能,所以它们的C型可以被调用。 例如,所有的功能相关的各种统计分布PDF / CDF和采样(例如,参见http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.rv_continuous.pdf.html#scipy。 stats.rv_continuous.pdf和http://www.johndcook.com/distributions_scipy.html )如果你在一个循环中调用与Python开销这些功能,这将是惊人缓慢。
谢谢。
您不能将C函数,如登录numpy的数组和numpy的没有一个C函数库,你可以用Cython调用。
NumPy的功能已经被优化过上numpy的阵列被调用。 除非你有一个非常独特的使用情况下,你不会看到来自重新实现numpy的功能作为C功能多少好处。 (这有可能是在numpy的某些功能未落实到位,在chich情况考虑提交你的输入情况的补丁。)然而,你带来了一个好点。
# A
from libc.math cimport log
for i in range(N):
r[i] = log(foo[i])
# B
r = np.log(foo)
# C
for i in range(n):
r[i] = np.log(foo[i])
在一般情况下,A和B应该有类似的运行时间,但应避免C和会慢得多。
更新
下面是scipy.stats.norm.pdf的代码,你可以看到它是写在numpy的和SciPy的通话蟒蛇。 有了这个代码,不C版,你必须把它称为“通过蟒”。 如果这是什么阻碍了你,你就需要重新植入它在C /用Cython,但首先我会非常仔细地花一些时间剖析代码,看看是否有任何低悬果后首先去了。
def pdf(self,x,*args,**kwds):
loc,scale=map(kwds.get,['loc','scale'])
args, loc, scale = self._fix_loc_scale(args, loc, scale)
x,loc,scale = map(asarray,(x,loc,scale))
args = tuple(map(asarray,args))
x = asarray((x-loc)*1.0/scale)
cond0 = self._argcheck(*args) & (scale > 0)
cond1 = (scale > 0) & (x >= self.a) & (x <= self.b)
cond = cond0 & cond1
output = zeros(shape(cond),'d')
putmask(output,(1-cond0)+np.isnan(x),self.badvalue)
if any(cond):
goodargs = argsreduce(cond, *((x,)+args+(scale,)))
scale, goodargs = goodargs[-1], goodargs[:-1]
place(output,cond,self._pdf(*goodargs) / scale)
if output.ndim == 0:
return output[()]
return output
文章来源: How to call numpy/scipy C functions from Cython directly, without Python call overhead?