添加维度不同的数组
假设我有一个二维的Numpy数组:
>>> a = np.random.random((4,6))
我想把一个一维数组加到每一行:
>>> c = np.random.random((6,))
>>> a + c
这样做是可以的。但是如果我想把一个一维数组加到每一列,就会出错:
>>> b = np.random.random((4,))
>>> a + b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape
我可以通过使用 np.newaxis
来解决这个问题:
>>> a + b[:,np.newaxis]
这样就能按预期工作了。
那么,怎样的形状匹配规则可以避免使用np.newaxis呢?是不是说Numpy数组形状的最后一个元素必须匹配?这个规则在更高维度的情况下也适用吗?比如,下面这个是可以的:
>>> a = np.random.random((2,3,4,5))
>>> b = np.random.random((4,5))
>>> a + b
所以我的问题是,这些规则有没有地方可以查到?这种行为是否可靠,还是说最好总是使用np.newaxis?
2 个回答
1
让我看看我是否理解了...
>>> from numpy import ones, newaxis
>>> A = ones((4,3)) # 4 rows x 3 cols
>>> A.shape
(4, 3)
>>> A
array([[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]])
>>>
>>> ones((4,1)) # 4 rows x 1 col
array([[ 1.],
[ 1.],
[ 1.],
[ 1.]])
>>> A + ones((4,1))
array([[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.]])
>>>
>>> ones((1,3)) # 1 row x 3 cols
array([[ 1., 1., 1.]])
>>> A + ones((1,3))
array([[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.]])
>>>
>>> B = ones((3,)) # a 1D array
>>> B
array([ 1., 1., 1.])
>>> B.shape
(3,)
>>> A + B
array([[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.]])
>>>
>>> C = ones((4,)) # a 1D array
>>> C.shape
(4,)
>>> C
array([ 1., 1., 1., 1.])
>>> A + C
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape
>>>
>>> D = C[:,newaxis]
>>> D.shape
(4, 1)
>>> A + D
array([[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.]])
当我们要把一个4行3列的矩阵和一个有3个元素的一维数组相加时,这个操作是成功的。
但是,如果我们想把同样的4行3列的矩阵和一个有4个元素的一维数组相加,那就失败了。
>>> D = C[:,newaxis]
这个操作会把C转换成一个形状合适的二维矩阵。
14
这是numpy的一个独特功能,叫做“广播”: 如果你可以把一个向量和一个标量相乘,那为什么不可以把一个矩阵和一个向量相乘呢?就像在第一个情况下,向量的每个元素都和标量相乘一样,在第二种情况下,矩阵每一行的每个单元格都和对应的向量元素相乘。
广播的实现有四条规则,虽然这些规则的表述有点复杂,但一旦理解后其实很直观:
- 所有维度
ndim
小于最大ndim
的输入数组,其形状前面会加上1。- 输出形状每个维度的大小是所有输入在该维度的大小中的最大值。
- 如果某个输入在特定维度的大小要么和输出在该维度的大小相同,要么大小为1,那么这个输入就可以参与计算。
- 如果某个输入在其形状的某个维度的大小为1,那么在该维度的所有计算中都会使用该维度的第一个数据项。换句话说,
ufunc
的计算不会在这个维度上移动(该维度的步长为0)。
例如,
在以下三种情况下,这种操作是可能的(不会出现你提到的shape mismatch
错误):
- 所有数组的形状完全相同。
- 所有数组的维度数量相同,并且每个维度的长度要么是相同的长度,要么是1。
- 维度过少的数组可以在其形状前面加上一个长度为1的维度,以满足第二条规则。
更多的例子可以在我最近的关于广播的文章中找到 [1] 或者在官方文档中 [2]。
参考资料