2016-11-18 16 views
0

私は多くの行列を追加しています。行列が[M1、M2 ...、M_n]であるとしましょう。簡単な方法は、X + = M、動作中numpyで行列加算を行う効率的な方法

X = np.zeros() 
for M in matrices: 
    X += M 

ある次に、PythonはX用の+ =が実行されるたびに新しいメモリを作成するのですか?そのような場合、それは非効率的なようです。 Xの新しいメモリを作成せずにインプレース操作を行う方法はありますか?

+0

「[M1、M2 ...、M_n]」とまったく同じですか?それは配列のリストですか?それのサンプルを追加しますか? – Divakar

+0

@Divakar私はそれが行列のリストだと思う。 – TuanDT

+0

@Divakar、Mはnp.ndarrayです。 – DSKim

答えて

1

これは動作しますが、より速く私のマシンではありません:あなたはMemoryErrorを取得しない限り

numpy.sum(matrices, axis=0) 
0

、numpyの第二の推測のメモリ使用量にしようとすると努力する価値はありません。コンパイルされたコードを知っている開発者に任せてください。

しかし、私たちはいくつかの時間テストを行うことができます。それは本当に重要な問題ですね。

いいサイズのアレイを100回追加してテストします。第一の軸を横切る+ =

In [480]: %%timeit 
    ...: X=np.zeros_like(M) 
    ...: for _ in range(100): X+=M 
    ...: 
1 loop, best of 3: 627 ms per loop 

またはサイズのアレイを作る(100、1000、1000)及び適用np.sum

In [479]: M=np.ones((1000,1000)) 

あなた反復アプローチ。

In [481]: timeit np.sum(np.array([M for _ in range(100)]),axis=0) 
1 loop, best of 3: 1.54 s per loop 

を使用し、np.add ufuncを使用します。 reduceでは、リスト内のすべての値に順次適用できます。私はrange(1000)を使用する場合

In [482]: timeit np.add.reduce([M for _ in range(100)]) 
1 loop, best of 3: 1.53 s per loop 

np.sum場合は私にMemoryErrorを与えます。私は(1000,1000,1000)配列を保持するのに十分なメモリがありません。リストから配列を作成するadd.reduceと同じです。

通常、カバーの下にある+=は隠されており、通常は私たちの心配はありません。しかし、カバーの下にピークをufunc.atを見て:https://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.at.html#numpy.ufunc.at

オペランドの場所の操作でバッファなし実行「」「インデックス」で指定した要素のために。 ufuncを追加する場合、このメソッドは[indexes] + = bと同等ですが、複数回インデックスされた要素に対して結果が累積される点が異なります。

したがってX+=Mは、合計をバッファに書き込み、そのバッファをXにコピーします。一時バッファがありますが、最終的なメモリ使用量は変わりません。 しかし、バッファの作成とコピーは高速なCコードで行われます。

np.add.atバッファリングされたアクションがいくつかの問題(重複インデックス)を作成するケースを処理するために追加されました。

したがって、一時的なバッファは回避されますが、かなりのスピードのコストがかかります。おそらくそれを遅くする追加されたインデックス機能です。 (もっと公平なadd.atテストがあるかもしれませんが、確かにこの場合は役に立ちません。)

In [491]: %%timeit 
    ...: X=np.zeros_like(M) 
    ...: for _ in range(100): np.add.at(X,(slice(None),slice(None)),M) 
1 loop, best of 3: 19.8 s per loop 
関連する問題