不同维度的纽比阵列广播

2024-09-22 20:35:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我有点被纽比的广播规则搞糊涂了。假设您要执行高维数组的轴方向标量积,以将数组维数减少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不能工作?在

干杯


Tags: fromimportnumpy规则oneszeros数组this
3条回答

np.dot(a, b)操作over the last axis of a and the second-to-last of b。因此,对于您的问题中的特定情况,您可以始终使用:

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

如果要保持v.dot(a)顺序,则需要将轴放置到位,这可以通过^{}轻松实现:

^{2}$

我不太喜欢np.dot,除非是为了明显的矩阵或向量乘法,因为在使用可选的out参数时,它对输出数据类型非常严格。Joe Kington已经提到过了,但是如果你要做这种事情,就要习惯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

在这种特殊情况下,也可以使用^{}。在

import numpy as np

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

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

这就产生了:

^{2}$

axes=(0,2)表示{}应该在v中的第一个轴和{}中的第三个轴求和。(还可以看看^{},它更灵活,但如果不习惯这种表示法,则更难理解。)

如果考虑速度,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总是更快,但由于开销恒定,对于大型数组来说,这种差异不太明显。)

您可以使用^{}进行此操作:

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

我认为V03不起作用的原因是,它与:

^{2}$

也就是说,它试图沿着A的最外轴计算点积。在

相关问题 更多 >