我试图在不使用np.repeat
创建大尺寸的情况下找出执行以下添加操作的好方法。如果使用np.repeat
并且添加是最好的解决方案,请告诉我。
我也很担心广播在这种情况下做了什么。基本上我有一个4d矩阵,我想在第一和第二个索引中添加一个2d矩阵,同时在索引0和索引3中执行此操作。
这可以正常使用
a = np.arange(64).reshape((2,4,4,2)).astype(float)
b = np.ones((2,2))
a[:, 0:2, 0:2, : ] += b
这会引发错误。这样做的好方法是什么?
a[:, 0:3, 0:3, :] += np.ones((3,3))
这有效,但不是我想做的事
c = np.arange(144).reshape(3,4,4,3).astype(float)
c[:, 0:3, 0:3, :] += np.ones((3,3))
答案 0 :(得分:3)
您可以从头开始包含空轴:
a[:, 0:3, 0:3, :] += np.ones((3,3,1)) # 1 broadcasts against any axis
类似的你应该使用:
a[:, 0:2, 0:2, : ] += np.ones((2,2,1))
因为你(可能是无意中)在第三和第四轴上播放了这些。我想你想把它广播到第二和第三,对吗?
此外,您始终可以使用np.expand_dims
和axis=-1
添加维度:
>>> np.expand_dims(np.ones((2, 2)), axis=-1).shape
(2, 2, 1)
或使用None
或np.newaxis
切片(它们是等效的!):
>>> np.ones((2, 2))[None, :, :, np.newaxis].shape
(1, 2, 2, 1)
第一个None
不是正确广播所必需的,但最后一个是!
在这种情况下,重要的是要提到从最后一个维度开始的numpy广播。因此,如果您有两个数组,则每个维度从最后一个开始必须具有相同的形状,或者其中一个必须为1(如果一个为1则沿着此轴广播!)。这就是a[:, 0:2, 0:2, : ]
工作的原因:
>>> a[:, 0:2, 0:2, : ].shape
(2, 2, 2, 2)
>>> b.shape
(2, 2)
所以最后一个维度相等(两个2
),倒数第二个维度相等(两个2
)。但是:
>>> np.ones((2,2,1)).shape
(2, 2, 1)
最后一个是2
和1
所以广播np.ones((2,2,1))
的最后一个轴,而第二个和第三个维度相等(所有2
)所以numpy使用了元素那里的运作。
答案 1 :(得分:2)
要对齐要添加的数组的轴,我们需要在末尾插入一个新轴,如下所示 -
a[:, 0:3, 0:3, :] += np.ones((3,3))[...,None]
让我们来研究这里的形状:
In [356]: a[:, 0:3, 0:3, :].shape
Out[356]: (2, 3, 3, 2)
In [357]: np.ones((3,3)).shape
Out[357]: (3, 3)
In [358]: np.ones((3,3))[...,None].shape
Out[358]: (3, 3, 1)
Input1 (a[:, 0:3, 0:3, :]) : (2, 3, 3, 2)
Input2 (np.ones((3,3))[...,None]) : (3, 3, 1)
请记住,广播规则规定单例维度(带lengths = 1
的维度)将广播到与其他非单例维度的长度匹配。此外,未列出的维度实际上默认长度为1
。
所以,这是可播放的,现在可以使用。
第2部分:为什么以下有效?
c = np.arange(144).reshape(3,4,4,3).astype(float)
c[:, 0:3, 0:3, :] += np.ones((3,3))
再次研究形状 -
In [363]: c[:, 0:3, 0:3, :].shape
Out[363]: (3, 3, 3, 3)
In [364]: np.ones((3,3)).shape
Out[364]: (3, 3)
Input1 (c[:, 0:3, 0:3, :]) : (3, 3, 3, 3)
Input2 (np.ones((3,3))) : (3, 3)
再次通过可播放的规则这很好,所以这里没有错误,但结果不是预期的。