2011-01-28 8 views
2

私のプログラムの速度に問題があります。私は巨大な配列の中の4人の隣人の平均を計算したいと思う。ここに私のコードの一部があります。最後の行を変更する方法はありますか?それとも別の配列を使うべきですか?巨大な配列の隣人の平均を計算するプログラムを加速する

for a in np.arange(100000): 
    for x in np.arange(size): 
     for y in np.arange(size): 
      if unchangeableflag[x*size+y] == 0: 
       vnew[x*size+y] = (v[(x+1)*size+y] + v[(x-1)*size+y] + v[x*size+y+1] + v[x*size+y-1])/4.0 
+0

なぜ 'A'以上のループ?反復収束を達成したいですか? –

+0

これはhttp://codereview.stackexchange.com/です(私は正しいですか?) – Donovan

+0

@Alberteddu cool! – kame

答えて

4

ループはまったく必要ありません。 vvnewunchangeableflagsize*sizeエントリを持つ1次元配列であると仮定すると、あなたは

v = v.reshape(size, size) 
vnew = vnew.reshape(size, size) 
unchangeableflag = unchangeableflag.reshape(size, size) 
average = v[1:-1, 2:] 
average += v[1:-1, :-2] 
average += v[2:, 1:-1] 
average += v[-2:, 1:-1] 
average /= 4.0 
vnew[1:-1, 1:-1][unchangeableflag[1:-1, 1:-1] == 0] = average 

を行うことができますしかし、あなたは実際に達成するために何をしようとしていますか?これはあなたが離散ラプラシアンのいくつかのアプリケーションから逃げることができるように疑わしいように見えます。

(これはvは、浮動小数点数が含まれていることを前提としています。V' `のdtypeがサイム整数型である場合、あなたは若干の修正が必要になります。)

+0

私はいつも一番外側の線が緩んだと思います。右? – kame

+1

@kame:あなた自身のコードは、境界上でやや未定義の動作をしています。境界で何をすべきかを定義すれば、それはもちろん組み込むことができます。 –

+2

@kame - numpyとscipyの畳み込み関数は、境界がどのように扱われるかについていくつかの異なるアプローチを可能にします。 – tom10

1

不確定ですが、不変の部分を削除できます。

for a in np.arange(100000): 
    for x in np.arange(size): 
     for y in np.arange(size): 
      t = x*size+y 
      if unchangeableflag[t] == 0: 
       vnew[t] = (v[t+size] + v[t-size] + v[t+1] + v[t-1])/4.0 
+0

4で割る代わりに、ビットを右に2回シフトすることができます。 vnet [t] =(v [t + size] + v [t-size] + v [t + 1] + v [t -1]); vnet [t] >> = 2; – tdobek

+0

今は18%高速です。 :) – kame

+0

@tdobek何ですか?これを説明できますか? – kame

3

あなたはscipyのダウンロードのconvolution filtergeneric_filterを使用して検討すべきです。これは依然として計算集約的ですが、ループ処理よりも高速です。通常、このタイプの平均化を行う場合、中心要素も含まれます。これらのソリューションは、多次元配列にも適用されます。

from scipy import ndimage 
footprint = scipy.array([[0,0.25,0],[0.25,0,0.25],[0,0.25,0]]) 
filtered_array = scipy.convolve(array, footprint) 

OR

from scipy import ndimage 
def myfunction(window): 
    return (window[0,1] + window[1,0] + window[1,2] + window[2,1])/4 
filtered_array = scipy.generic_filter(array, myfunction, size=3) 
+0

これらのソリューションは簡潔ですが、最速ではありません。特に第2の解決法は非常に遅い。最初の解決策では、 'scipy.convolve'の代わりに' ndimage.convolve() 'を使いたいでしょう。なぜなら、後者は1d配列だけのためです。さらに、両方の解決策は、元の投稿の不思議な「変更不可能なフラグ」を無視します。 –

+0

convolve1dは1次元配列、convolveは多次元バージョンです。私がndimageをインポートする方法のため、私はscipy.ndimage.convolveを指定する必要はないと思います。私は、よりシンプルで効果的な代替案の例を提供するよりも、元のコードを維持して修正することに心配していません。 – Benjamin

+4

'scipy.convolve'と' scipy.ndimage。「畳み込み」は全く同じ機能ではありません! 「裸の」「scipy」名前空間にあるものは、歴史的な理由からちょうどそこにあります(つまり、いくつかのデフォルトが違うにもかかわらず、numpy関数です)。 scipyの機能のすべては、 'scipy.ndimage'、' scipy.special'、 'scipy.signal'などの他の名前空間にあります。それ以外にも、これは確かに畳み込みで行うことができます。 –

関連する問題