7

numpy のブロードキャスト ルールに少し戸惑いました。より高い次元の配列の軸方向のスカラー積を実行して、配列の次元を 1 つ減らしたいとします (基本的には、1 つの軸に沿って加重合計を実行します)。

from numpy import *

A = ones((3,3,2))
v = array([1,2])

B = zeros((3,3))

# V01: this works
B[0,0] = v.dot(A[0,0])

# V02: this works
B[:,:] = v[0]*A[:,:,0] + v[1]*A[:,:,1] 

# V03: this doesn't
B[:,:] = v.dot(A[:,:]) 

V03 が機能しないのはなぜですか?

乾杯

4

3 に答える 3

4

np.dot(a, b)a の最後の軸と b の最後から 2 番目の軸を操作します。したがって、質問の特定のケースでは、いつでも次のようにすることができます:

>>> a.dot(v)
array([[ 3.,  3.,  3.],
       [ 3.,  3.,  3.],
       [ 3.,  3.,  3.]])

順序を維持したい場合はv.dot(a)、軸を所定の位置に配置する必要があります。これは、次の方法で簡単に実現できますnp.rollaxis

>>> v.dot(np.rollaxis(a, 2, 1))
array([[ 3.,  3.,  3.],
       [ 3.,  3.,  3.],
       [ 3.,  3.,  3.]])

オプションのパラメーターnp.dotを使用する場合、出力 dtype について非常に厳密であるため、明らかな行列またはベクトルの乗算でない限り、あまり好きではありません。outジョー・キングトンはすでにそれについて言及しましたが、この種のことを行う場合は、慣れてnp.einsumください: 構文のコツをつかむと、物事を再形成することを心配するのに費やす時間を最小限に抑えることができます:

>>> a = np.ones((3, 3, 2))
>>> np.einsum('i, jki', v, a)
array([[ 3.,  3.,  3.],
       [ 3.,  3.,  3.],
       [ 3.,  3.,  3.]])

この場合、関連性が高すぎるというわけではありませんが、途方もなく高速でもあります。

In [4]: %timeit a.dot(v)
100000 loops, best of 3: 2.43 us per loop

In [5]: %timeit v.dot(np.rollaxis(a, 2, 1))
100000 loops, best of 3: 4.49 us per loop

In [7]: %timeit np.tensordot(v, a, axes=(0, 2))
100000 loops, best of 3: 14.9 us per loop

In [8]: %timeit np.einsum('i, jki', v, a)
100000 loops, best of 3: 2.91 us per loop
于 2013-03-08T20:40:43.980 に答える
3

tensordotこの特定のケースでは、も使用できます。

import numpy as np

A = np.ones((3,3,2))
v = np.array([1,2])

print np.tensordot(v, A, axes=(0, 2))

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

array([[ 3.,  3.,  3.],
       [ 3.,  3.,  3.],
       [ 3.,  3.,  3.]])

は、 の最初の軸と の 3 番目の軸を合計する必要がaxes=(0,2)あることを示します。( も見てください。これはより柔軟ですが、表記法に慣れていないと理解しにくいものです。)tensordotvAeinsum

速度が考慮される場合は、小さな配列にtensordot使用するよりもかなり高速です。apply_along_axes

In [14]: A = np.ones((3,3,2))

In [15]: v = np.array([1,2])

In [16]: %timeit np.tensordot(v, A, axes=(0, 2))
10000 loops, best of 3: 21.6 us per loop

In [17]: %timeit np.apply_along_axis(v.dot, 2, A)
1000 loops, best of 3: 258 us per loop

tensordot(一貫して高速ですが、一定のオーバーヘッドがあるため、大規模な配列の場合、違いはそれほど明白ではありません。)

于 2013-03-08T17:59:04.900 に答える
2

これに使用できますnumpy.apply_along_axis()

In [35]: np.apply_along_axis(v.dot, 2, A)
Out[35]: 
array([[ 3.,  3.,  3.],
       [ 3.,  3.,  3.],
       [ 3.,  3.,  3.]])

V03うまくいかないと思う理由は、次の場合と変わらないからです。

B[:,:] = v.dot(A) 

つまり、 の最も外側の軸に沿って内積を計算しようとしAます。

于 2013-03-08T15:07:53.617 に答える