最近、numpy配列の反復処理に関するさまざまな手法について多くのことを読んできました。コンセンサスはまったく反復しないようです(たとえば、a comment hereを参照)。あまりにも多くの質問がありますが、 "反復"(反復しない)と以前の値へのアクセスを組み合わせなければならないので、私のケースは少し異なります。複数の配列を繰り返し処理し、現在の要素と前の要素を処理する効率的な方法はありますか?
X
のリスト内にN個(Nは小さく、通常は4個、最大7個まで可能)1D numpy配列float128
があり、すべての配列が同じサイズであるとします。あなたに少し洞察を与えるために、これらはPDEの統合によるデータです。各配列は1つの関数を表しています。私はポアンカレセクションを適用したいと思います。残念ながら、アルゴリズムはメモリと時間の両方で効率的でなければなりません。なぜならこれらの配列はそれぞれ〜1Gbであり、ボードには4GbのRAMしかないからです(私はちょうどnumpy配列のmemmapのことを学びました。普通のものの)。
これらの配列のうちの1つは、他の配列を「フィルタリング」するために使用されるので、secaxis = X.pop(idx)
から始めます。今度は、(secaxis[i-1] > 0 and secaxis[i] < 0) or (secaxis[i-1] < 0 and secaxis[i] > 0)
のインデックスのペアを見つけて、残りの配列に単純な代数変換を適用すると、X
(そして結果を保存)する必要があります。言及する価値は、この操作中にデータを無駄にしないでください。
これを行うには複数の方法がありますが、どれも効率的(そして十分にエレガント)ではありません。一つは、あなただけで反復C-ようなアプローチであり、forループ:
import array # better than lists
res = [ array.array('d') for _ in X ]
for i in xrange(1,secaxis.size):
if condition: # see above
co = -secaxis[i-1]/secaxis[i]
for j in xrange(N):
res[j].append((X[j][i-1] + co*X[j][i])/(1+co))
これは明らかに非常に非効率的でないPython的な方法以外にもあります。
もう一つの方法は、numpy.nditerを使用することですが、私はそれが一度に複数のアレイを反復することができますけれども1は、前の値にアクセスする方法をまだ考え出したていない:
# without secaxis = X.pop(idx)
it = numpy.nditer(X)
for vec in it:
# vec[idx] is current value, how do you get the previous (or next) one?
第三の可能性は、最初にあります効率的なnumpyスライスで検索されたインデックスを見つけて、それらを一括乗算/加算に使用します。私は今のところこれを好む:
res = []
inds, = numpy.where((secaxis[:-1] < 0) * (secaxis[1:] > 0) +
(secaxis[:-1] > 0) * (secaxis[1:] < 0))
coefs = -secaxis[inds]/secaxis[inds+1] # array of coefficients
for f in X: # loop is done only N-1 times, that is, 3 to 6
res.append((f[inds] + coefs*f[inds+1])/(1+coefs))
しかし、これは一見7 + 2 *(N - 1)で行われている渡し、さらに、Iアドレッシングのsecaxis[inds]
種類についてはよく分からない(それはスライスし、一般的にされていません最初の方法と同じようにすべての要素をインデックスで見つける必要がありますか?)。
最後に、私はまた、itertoolsを使用してみたのだが、私は関数型プログラミングに精通していないよという事実から生じるかもしれない怪物とあいまいな構造をもたらした:
def filt(x):
return (x[0] < 0 and x[1] > 0) or (x[0] > 0 and x[1] < 0)
import array
from itertools import izip, tee, ifilter
res = [ array.array('d') for _ in X ]
iters = [iter(x) for x in X] # N-1 iterators in a list
prev, curr = tee(izip(*iters)) # 2 similar iterators, each of which
# consists of N-1 iterators
next(curr, None) # one of them is now for current value
seciter = tee(iter(secaxis))
next(seciter[1], None)
for x in ifilter(filt, izip(seciter[0], seciter[1], prev, curr)):
co = - x[0]/x[1]
for r, p, c in zip(res, x[2], x[3]):
r.append((p+co*c)/(1+co))
だけでなく、このルックス非常に醜い、それはまた、完了するのに非常に多くの時間がかかります。
だから、私は次のような質問している:すべてのこれらのメソッドの
- は、3つ目は本当に最高ですか!もしそうなら、最後のものを取り除くために何ができるのですか?
- まだ他に優れたものはありますか?
- 好奇心から、nditerを使って問題を解決する方法はありますか?
- 最後に、numpy配列のmemmapバージョンを使用する方が良いでしょうか、それともおそらく動作が遅くなるのでしょうか?たぶん私はRAMに
secaxis
アレイをロードするだけで、ディスク上の他の人を保ち、3番目の方法を使用する必要がありますか? - (ボーナスの質問)等価長の1次元numpy配列のリストは、サイズがあらかじめわかっていない(ただしNは)N
.npy
のファイルをロードしたものです。 1つの配列を読み取ってから、2次元配列の配列に1つのメモリを割り当て(ここでわずかなメモリオーバヘッド)、その2次元配列に残りの読み取りを行う方が効率的でしょうか?