2013-04-16 21 views
15

私は、numpy.logのようないくつかのnumpy/scipy数学関数に大きく依存しているCythonで計算しようとしています。私はCythonのループで繰り返しnumpyの/ scipyのダウンロード機能を呼び出す場合、例えば、巨大なオーバーヘッドコストがあることに気づい:Python呼び出しのオーバーヘッドなしで直接numpy/scipy C関数をCythonから呼び出す方法は?

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ではなくnumpyのCの関数を呼び出すよりも、Pythonの経由するので、これはおそらく、非常に高価です直接。その行を次のように置き換えた場合:

from libc.math cimport log 
... 
# calling libc function 'log' 
value = log(2) 

これははるかに高速です。しかし、私がしようとすると、libc.math.logするnumpyの配列を渡す:

TypeError: only length-1 arrays can be converted to Python scalars 

私の質問

は次のとおりです:

  1. をすることは可能ですがこのエラーを与える

    cdef np.ndarray[long, ndim=1] foo = np.array([1, 2, 3]) 
    log(foo) 
    

    Cの関数を呼び出してnumpyの配列を渡しますか?または、これはスカラー値でのみ使用できます(例えば、上記のfoo配列にそれを適用したい場合など)。

  2. 同様の方法で、Cからscipy関数を直接呼び出すことはできません。 Pythonのオーバーヘッド?どのようにscipyのC関数ライブラリをインポートできますか?

具体例:あなたはCythonでforループ内のスカラ値にscipyのダウンロード用のまたはnumpyのの便利な統計機能(例えばscipy.stats.*)の多くを呼びたいと言いますか? Cythonでこれらの関数を再実装するのは夢中なので、C言語のバージョンを呼び出す必要があります。たとえば、pdf/cdfに関連するすべての関数とさまざまな統計分布からのサンプリング(例えばhttp://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.rv_continuous.pdf.html#scipy.stats.rv_continuous.pdfhttp://www.johndcook.com/distributions_scipy.htmlを参照)これらの関数をPythonのオーバーヘッドでループ内で呼び出すと、非常に遅くなるでしょう。

ありがとうございました。

+0

「scipy.stats」pdfなど関数は主にPythonで実装されています。一度に多くの数値を処理することでオーバーヘッドを避けることができます。 –

答えて

2

ログオン数の配列などのC関数を適用することはできず、numpyにはcythonから呼び出せるC関数ライブラリがありません。

Numpy関数はnumpy配列で呼び出されるように既に最適化されています。非常にユニークなユースケースを持っていない限り、C関数としてnumpy関数を再実装することで多くのメリットは得られません。 (numpyのいくつかの関数はうまく実装されていない可能性があります。ちなみに、インポートをパッチとして提出することを検討してください)。しかし、あなたは良い点を挙げています。

# 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は避けてはるかに遅くなります。あなたはそれがnumpyのscipyのダウンロードと呼び出しで、Pythonで書かれて見ることができるようにここで

更新

は、scipy.stats.norm.pdfためのコードです。このコードのCバージョンはありません。あなたは "Pythonを通して"呼び出す必要があります。これがあなたを抱きしめているのであれば、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 
+1

しかし、私はベクトル化できないコードでforループを書く必要があり、そのループ内の特定のnumpy関数(ベクトルではなくスカラー値)を使いたいのですが?私はCythonでそれらのnumpy関数を再実装する必要がありますか?それは非常にばかげているようです。あなたが指摘したように、良いものではないオプションCでのみ行うことができます – user248237dfsf

+0

その場合、最良の選択肢はcythonでこれらの関数を再実装し、オプションAを使用するかもしれません。どのnumpy関数をループ内で呼び出す必要がありますか? –

+2

統計に関連するさまざまな機能。私は詳細を持って私の答えを編集しました。たとえば、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)。それはちょうどCythonでそれを得るためにlibc.mathからのプリミティブを使用してすべてのそれらのpdfsを再実装するのは正しいとは思わない...より良い方法でなければならない? – user248237dfsf

関連する問題