非常に大きなデータ マトリックス (約 15,000 x 15,000、double 型) を作成および操作するコードのセクションを高速化しようとしています。今のところ、行列のサイズはそれほど重要ではないと思います。なぜなら、小さな 10 x 10 の行列でもスピードアップが見られないからです (実際、コンパイルされた cython コードは、小さな行列の場合、純粋な python よりも遅くなりますが、時間は大きな行列については、cython と python の間でほぼ同じです)。私は 1 週間だけ Python をコーディングしており (Matlab から新たに変換されました)、私は謙虚な化学エンジニアに過ぎないので、しばらくお待ちください。
コードの目的は、入力として 1D 配列 (長さ L) を取得することです。次に例を示します。
[ 16.66 16.85 16.93 16.98 17.08 17.03 17.09 16.76 16.67 16.72]
出力として行列 (高さ L、幅 L-1) を生成します。
[[ 16.66 16.85 16.93 16.98 17.08 17.03 17.09 16.76 16.67]
[ 16.85 16.93 16.98 17.08 17.03 17.09 16.76 16.67 16.72]
[ 16.93 16.98 17.08 17.03 17.09 16.76 16.67 16.72 0. ]
[ 16.98 17.08 17.03 17.09 16.76 16.67 16.72 0. 0. ]
[ 17.08 17.03 17.09 16.76 16.67 16.72 0. 0. 0. ]
[ 17.03 17.09 16.76 16.67 16.72 0. 0. 0. 0. ]
[ 17.09 16.76 16.67 16.72 0. 0. 0. 0. 0. ]
[ 16.76 16.67 16.72 0. 0. 0. 0. 0. 0. ]
[ 16.67 16.72 0. 0. 0. 0. 0. 0. 0. ]
[ 16.72 0. 0. 0. 0. 0. 0. 0. 0. ]]
上記の例と以下のコードから、私が達成しようとしていることは明らかです。アルゴリズムは非常に大きな行列にスケーリングする必要がありますが、現在はエラーなしで実行されていますが、単に遅いだけです!
これが私のcythonコードです:
from scipy.sparse import spdiags
import numpy as np
cimport numpy as np
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def sfmat(np.ndarray[double, ndim=1] data):
cdef int h = data.shape[0]
cdef np.ndarray[double, ndim=2] m = np.zeros([h, h-1])
m = np.flipud(spdiags(np.tril(np.tile(data,[h-1,1]).T,0),range(1-h,1), h, h-1).todense())
return m
読みやすいかもしれない、より詳細なコードも試しました。
from scipy.sparse import spdiags
import numpy as np
cimport numpy as np
cimport cython
DTYPE = np.float
ctypedef np.float_t DTYPE_t
@cython.boundscheck(False)
@cython.wraparound(False)
def sfmat(np.ndarray[DTYPE_t, ndim=1] data):
assert data.dtype == DTYPE
cdef int h = data.shape[0]
cdef np.ndarray[DTYPE_t, ndim=2] m = np.zeros([h, h-1], dtype=DTYPE)
cdef np.ndarray[DTYPE_t, ndim=2] s1 = np.zeros([h, h-1], dtype=DTYPE)
cdef np.ndarray[DTYPE_t, ndim=2] s2 = np.zeros([h, h-1], dtype=DTYPE)
cdef np.ndarray[DTYPE_t, ndim=2] s3 = np.zeros([h, h-1], dtype=DTYPE)
s1 = np.tile(data,[h-1,1]).T
s2 = np.tril(s1,0)
s3 = spdiags(s2,range(1-h,1), h, h-1).todense()
m = np.flipud(s3)
return m
cython の実装に関するヘルプをいただければ幸いです。このアルゴリズムを高速化する他の方法があれば、それも役立ちます。助けてくれてありがとう!
私はこれに慣れていないので、ここに詳細があります。私は 64 ビットの Windows 7 Pro を実行しており、Windows SDK C/C++ コンパイラを使用して cython コードを正常にコンパイルしています。(私はgithub hereの指示に従って成功しました)。単純な「hello world」の cython の例は、64 ビット モードで正常にコンパイルおよび実行されます。また、上記のコードもエラーなしでコンパイルおよび実行されます。15,000 x 15,000 マトリックス全体を操作するには、64 ビット アーキテクチャが必要です。少なくとも私はそう信じています。32 ビット用にコンパイルした後にコードを実行すると、メモリ エラーが発生するからです。この質問では、マトリックスを小さなチャンクに分割することは不可能であると仮定してください。この質問に答えるために他に必要な情報があれば教えてください。
乾杯、科学者R
アップデート
for ループを回避するのが最善の方法だと思いましたが、spdiags が主なボトルネックです。したがって、新しいアルゴリズムはよりうまく機能します (私のコンピューターでは 4 倍の改善):
import numpy as np
cimport numpy as np
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def sfmat(np.ndarray[double, ndim=1] data):
cdef int i
cdef np.ndarray[double, ndim=2] m = np.zeros([data.shape[0], data.shape[0]-1])
for i in range(data.shape[0]-1):
m[:,i] = np.roll(data,-i);
return m
しかし、Cython は純粋な Python よりも改善されていません。助けてください。コメンテーターが指摘しているように、アルゴリズムをより最適化する以外に、これを改善する方法はないかもしれませんが、私は期待しています。ありがとう!また、より高速なアルゴリズム、cython または python はありますか?