不同尺寸的NumPy Array广播
我对numpy的广播规则有些困惑.假设您要执行高维数组的轴向标量积,以将数组维数减小一(基本上是沿一个轴执行加权求和):
I a little confused by the broadcasting rules of numpy. Suppose you want to perform an axis-wise scalar product of a higher dimension array to reduce the array dimension by one (basically to perform a weighted summation along one axis):
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不起作用?
Why does V03 not work?
欢呼
np.dot(a, b)
操作在a的最后一个轴和b的倒数第二个上.因此,对于您的问题中的特殊情况,您可以始终选择:
np.dot(a, b)
operates over the last axis of a and the second-to-last of b. So for your particular case in your question,you could always go with :
>>> a.dot(v)
array([[ 3., 3., 3.],
[ 3., 3., 3.],
[ 3., 3., 3.]])
If you want to keep the v.dot(a)
order, you need to get the axis into position, which can easily be achieved with np.rollaxis
:
>>> v.dot(np.rollaxis(a, 2, 1))
array([[ 3., 3., 3.],
[ 3., 3., 3.],
[ 3., 3., 3.]])
我不太喜欢np.dot
,除非它用于明显的矩阵或矢量乘法,因为使用可选的out
参数时,它对输出dtype的要求非常严格. Joe Kington已经提到过它,但是如果您打算做这种事情,请习惯np.einsum
:一旦掌握了语法,它将减少您花费在担心重塑事情上的时间最少:
I don't like np.dot
too much, unless it is for the obvious matrix or vector multiplication, because it is very strict about the output dtype when using the optional out
parameter. Joe Kington has mentioned it already, but if you are going to be doing this type of things, get used to np.einsum
: once you get the hang of the syntax, it will cut down the amount of time you spend worrying about reshaping things to a minimum:
>>> a = np.ones((3, 3, 2))
>>> np.einsum('i, jki', v, a)
array([[ 3., 3., 3.],
[ 3., 3., 3.],
[ 3., 3., 3.]])
并非在这种情况下太相关了,但是它也非常快:
Not that it is too relevant in this case, but it is also ridiculously fast:
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