3

私はいくつかの厄介なものに問題があります。コピーではなく、スライスしたデータのビューとしてスライスを返すことで、異常な動作をするためにnumpy配列が必要です。だからここに私がやりたいことの例があります:

次のような単純な配列があるとします。

a = array([1, 0, 0, 0])

次のような構文を使用して、配列内の連続するエントリを(左から右に移動して)配列からの前のエントリで更新したいと思います。

a[1:] = a[0:3]

これにより、次の結果が得られます。

a = array([1, 1, 1, 1])

またはこのようなもの:

a[1:] = 2*a[:3]
# a = [1,2,4,8]

さらに説明するために、次のような動作が必要です。

for i in range(len(a)):
    if i == 0 or i+1 == len(a): continue
    a[i+1] = a[i]

numpyのスピードが欲しい以外は。

numpyのデフォルトの動作はスライスのコピーを取得することなので、実際に取得するのは次のとおりです。

a = array([1, 1, 0, 0])

私はすでにこの配列をndarrayのサブクラスとして持っているので、必要に応じてさらに変更を加えることができます。左側のスライスを更新するときに、右側のスライスを継続的に更新する必要があります。

私は夢を見ていますか、それともこの魔法は可能ですか?

更新:これはすべて、ガウス・ザイデル反復を使用して線形代数の問題を多かれ少なかれ解決しようとしているためです。これは調和関数を含む特殊なケースです。これは本当に必要ではなく、さらに混乱する可能性があるため、これに入るのを避けようとしましたが、ここで説明します。

アルゴリズムは次のとおりです。

while not converged:
    for i in range(len(u[:,0])):
        for j in range(len(u[0,:])):
            # skip over boundary entries, i,j == 0 or len(u)
            u[i,j] = 0.25*(u[i-1,j] + u[i+1,j] + u[i, j-1] + u[i,j+1])

右?ただし、これは2つの方法で実行できます。Jacobiでは、whileループが循環するまでに既に行った更新を考慮せずに、各要素を隣接する要素で更新します。ループで実行するには、配列をコピーしてから、コピーした配列から1つの配列を更新します。ただし、Gauss-Seidelは、i-1およびj-1エントリごとに更新済みの情報を使用するため、コピーは必要ありません。単一要素の更新ごとに配列が再評価されるため、ループは基本的に「認識」する必要があります。 。つまり、u [i-1、j]やu [i、j-1]のようなエントリを呼び出すたびに、前のループで計算された情報がそこにあります。

この遅くて醜いネストされたループの状況を、numpyslicingを使用した1行のきれいなコードに置き換えたいと思います。

u[1:-1,1:-1] = 0.25(u[:-2,1:-1] + u[2:,1:-1] + u[1:-1,:-2] + u[1:-1,2:])

ただし、結果はJacobiの反復になります。これは、スライスを取得するときに:u [:、-2,1:-1]データをコピーするため、スライスは行われた更新を認識しないためです。今でもnumpyはループしますよね?並列ではなく、Pythonでの並列操作のように見えるループへのより高速な方法です。スライスを取得するときに、コピーではなくポインタを返すようにnumpyをハッキングすることで、この動作を利用したいと思います。右?その後、numpyがループするたびに、そのスライスは「更新」されるか、実際には更新で発生したものを複製します。これを行うには、配列の両側にあるスライスをポインターにする必要があります。

とにかく、本当に賢い人がそこにいるなら、それは素晴らしいですが、私はほとんど自分自身を辞任して、唯一の答えはCでループすることだと信じています。

4

9 に答える 9

4

遅い答えですが、これはグーグルで判明したので、私はおそらくOPが望んでいたドキュメントを指しています。問題は明らかです。NumPyスライスを使用すると、一時的なものが作成されます。weave.blitzをすばやく呼び出してコードをラップし、一時的なものを取り除き、希望する動作を実現します。

詳細については、 PerformancePythonチュートリアルのweave.blitzセクションをお読みください。

于 2010-04-10T13:59:41.850 に答える
2

Accumulateは、あなたがやりたいと思われることを実行するように設計されています。つまり、配列に沿って操作を特権化することです。次に例を示します。

from numpy import *

a = array([1,0,0,0])
a[1:] = add.accumulate(a[0:3])
# a = [1, 1, 1, 1]

b = array([1,1,1,1])
b[1:] = multiply.accumulate(2*b[0:3])
# b = [1 2 4 8]

これを行う別の方法は、結果配列を入力配列として明示的に指定することです。次に例を示します。

c = array([2,0,0,0])
multiply(c[:3], c[:3], c[1:])
# c = [  2   4  16 256]
于 2009-10-19T21:13:02.000 に答える
1

それは正しい論理ではありません。説明には文字を使ってみます。

array = abcd要素としてa、b、c、dを含む画像。
ここで、は、上array[1:]の位置1(から始まる0)の要素からを意味します。
この場合:bcdそして、この場合、位置にある文字から3番目の文字(array[0:3]位置にある文字)までを意味します:。03-1'abc'

次のようなものを書く:
array[1:] = array[0:3]

意味:次のように置き換えbcdますabc

必要な出力を取得するには、Pythonで、次のようなものを使用する必要があります。

a[1:] = a[0]
于 2009-10-19T13:37:10.920 に答える
1

ループを使用するだけです。numpyをサブクラス化arrayし、適切なメソッドをある種のPythonブードゥーでオーバーライドする以外は、スライス演算子を希望どおりに動作させる方法をすぐに考えることはできません...しかし、もっと重要なのは、a[1:] = a[0:3]の最初の値を次の3つのスロットにコピーする必要があるという考えはa、私にはまったく無意味に思えます。あなたのコードを見る他の人を簡単に混乱させる可能性があると思います(少なくとも最初の数回)。

于 2009-10-19T07:49:35.740 に答える
1

スライスの割り当てと関係があるはずです。ただし、オペレーターは、ご存知かもしれませんが、予想される動作に従います。

>>> a = numpy.array([1,0,0,0])
>>> a[1:]+=a[:3]
>>> a
array([1, 1, 1, 1])

あなたの例がそうであるあなたの現実の問題にすでにゼロがあるなら、これはそれを解決します。それ以外の場合は、追加のコストで、ゼロを掛けるか、ゼロに割り当てることによって、それらをゼロに設定します(どちらか速い方)。

編集:私は別の考えを持っていました。あなたはこれを好むかもしれません:

numpy.put(a,[1,2,3],a[:3]) 
于 2009-10-19T13:03:14.137 に答える
1

Numpyは、setkey呼び出しを実行するときに、ターゲット配列が入力配列と同じであるかどうかをチェックしている必要があります。幸いなことに、それを回避する方法があります。まず、numpy.put代わりに使ってみました

In [46]: a = numpy.array([1,0,0,0])

In [47]: numpy.put(a,[1,2,3],a[0:3])

In [48]: a
Out[48]: array([1, 1, 1, 1])

そして、そのドキュメントから、flatitersを使用して試してみました(a.flat

In [49]: a = numpy.array([1,0,0,0])

In [50]: a.flat[1:] = a[0:3]

In [51]: a
Out[51]: array([1, 1, 1, 1])

しかし、これはあなたが考えていた問題を解決しません

In [55]: a = np.array([1,0,0,0])

In [56]: a.flat[1:] = 2*a[0:3]

In [57]: a
Out[57]: array([1, 2, 0, 0])

乗算は割り当ての前に行われるため、これは失敗します。必要に応じて並列ではありません。

Numpyは、まったく同じ操作をアレイ全体で並行して繰り返し適用できるように設計されています。numpy.cumsumより複雑なことを行うには、やのような関数で分解できない限り、numpy.cumprodscipy.weaveのようなものに頼るか、Cで関数を記述する必要があります(詳細については、PerfomancePythonページを参照してください)。 、私はweaveを使用したことがないので、それがあなたの望むことをすることを保証することはできません。)

于 2009-10-19T16:04:55.910 に答える
1

np.lib.stride_tricksを見ることができます。

これらの優れたスライドにはいくつかの情報があります:http: //mentat.za.net/numpy/numpy_advanced_slides/

スライド29から始まるstride_tricksを使用します。

私はこの質問について完全には明確ではありませんが、これ以上具体的なことを提案することはできません-おそらくcythonまたはfortranでf2pyまたはweaveを使用してそれを行うでしょうが。必要なすべての型注釈をcythonに追加するまでに、Fortranよりも明確に見えなくなると思うので、現時点ではFortranの方が好きです。

ここにこれらのアプローチの比較があります:

www。scipy。org / PerformancePython

(私は新しいユーザーなので、これ以上リンクを投稿することはできません)あなたのケースに似た例を使用してください。

于 2009-10-28T14:41:47.150 に答える
1

結局、私はあなたと同じ問題を思いついた。私はヤコビ反復とウィーバーを使用することに頼らなければなりませんでした:

 while (iter_n < max_time_steps):
        expr = "field[1:-1, 1:-1] = (field[2:, 1:-1] "\
                                                      "+ field[:-2, 1:-1]+"\
                                                      "field[1:-1, 2:] +"\
                                                      "field[1:-1, :-2] )/4."                                       

        weave.blitz(expr, check_size=0)

         #Toroidal conditions
        field[:,0] = field[:,self.flow.n_x - 2]
        field[:,self.flow.n_x -1] = field[:,1]

        iter_n = iter_n + 1

動作し、高速ですが、ガウス・ザイデルではないため、収束には少し注意が必要です。Gauss-Seidelをインデックス付きの従来のループとして実行する唯一のオプション。

于 2013-02-11T02:21:10.013 に答える
0

cでループする代わりにcythonを提案します。多くの中間ステップを使用して例を機能させるための派手な方法があるかもしれません...しかし、cでそれを書く方法をすでに知っているので、cython関数としてその簡単な少しを書いて、cythonの魔法で残りの作業は簡単です。

于 2009-10-21T20:54:35.127 に答える