2015-10-25 11 views
5

大きなNumPyの配列を計算することに興味があります。私は数字の束を含む大きな配列Aを持っています。私はこれらの数の異なる組み合わせの合計を計算したいと思います。データの構造は次のとおりです。大きなNumPyの乗算をベクトル化する

A = np.random.uniform(0,1, (3743, 1388, 3)) 
Combinations = np.random.randint(0,3, (306,3)) 
Final_Product = np.array([ np.sum(A*cb, axis=2) for cb in Combinations]) 

これを計算する方法がよりエレガントでメモリ効率のよい方法があるのですか? 3次元配列が含まれている場合は、np.dot()を使って作業するのが面倒です。

Final_Productの形状が理想的には(3743,306,1388)である必要があります。現在Final_Productは形状(306,3743,1388)のものですので、私はそこに着くために形を変えることができます。

答えて

5

np.dot()は、おそらくreshapingを含む余分なステップが含まれていない限り、希望の出力を与えません。ここでは余分なメモリのオーバーヘッドなしでそれを一発を行うにはnp.einsumを使用して1つのvectorizedアプローチだ -

M,N,R = A.shape 
Final_Product = A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N) 

ランタイムテストをし、出力を確認します -

Final_Product = np.einsum('ijk,lk->lij',A,Combinations) 

完全の場合は、先に述べたように、ここではnp.dotreshapingでです -

In [138]: # Inputs (smaller version of those listed in question) 
    ...: A = np.random.uniform(0,1, (374, 138, 3)) 
    ...: Combinations = np.random.randint(0,3, (30,3)) 
    ...: 

In [139]: %timeit np.array([ np.sum(A*cb, axis=2) for cb in Combinations]) 
1 loops, best of 3: 324 ms per loop 

In [140]: %timeit np.einsum('ijk,lk->lij',A,Combinations) 
10 loops, best of 3: 32 ms per loop 

In [141]: M,N,R = A.shape 

In [142]: %timeit A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N) 
100 loops, best of 3: 15.6 ms per loop 

In [143]: Final_Product =np.array([np.sum(A*cb, axis=2) for cb in Combinations]) 
    ...: Final_Product2 = np.einsum('ijk,lk->lij',A,Combinations) 
    ...: M,N,R = A.shape 
    ...: Final_Product3 = A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N) 
    ...: 

In [144]: print np.allclose(Final_Product,Final_Product2) 
True 

In [145]: print np.allclose(Final_Product,Final_Product3) 
True 
+0

ありがとうございます!私は@ajcrの答えが非常に役立つことも発見しました。テンソルを使用すると、 'np.einsum'で使用された時間が半減しました – Julien

+0

@Julien私はajcrのソリューションも好きです!私はそれがここで 'ドット'のものの簡潔なバージョンだと思う。 – Divakar

5

Inst dotのeadはtensordotです。あなたの現在の方法は同等です:

np.tensordot(A, Combinations, [2, 1]).transpose(2, 0, 1) 

正しい順序で軸を入れて最後にtransposeに注意してください。

tensordotのように、ファンクションはファーストBLAS/LAPACKライ​​ブラリを呼び出すことができます(インストールされている場合)ので、大きな配列ではうまくいくはずです。

+0

短くてシンプルな、私はそれが好きです! – Divakar

+0

@Divakar:ありがとう!私はまだ 'einsum'を好む:-) –

+0

私も! 'einsum'が3D配列を出力するときにこの感覚がありました。これは' 2D'配列や最良の 'スカラー 'に縮小するほど効率的ではありません。 – Divakar

関連する問題