我有一个广播错误,如下所示:
ValueError:操作数无法与形状(84,36((84,36210,45(一起广播
有办法解决这个问题吗?我试着使用np.transpose((在索引周围移动,以便遵守广播规则,但不知何故,我得到的答案不再正确。np.transpose((在这里到底做什么?
有多种方法可以进行广播。
使用转置
较长的方式是您尝试使用transpose
的方式。这里,由于array a
只有2个维度(它是最后2个维度(,所以您也可以将array b
的前2个维度设置为最后2个维-
a = np.random.random((84,36))
b = np.random.random((84,36,210,45))
c = b.transpose(2,3,0,1) + a #(210, 45, 84, 36) + (84, 36)
c = c.transpose(2,3,0,1) #transpose back to (84,36,210,45)
c.shape
(84, 36, 210, 45)
这里要澄清的是,b.transpose(2,3,0,1)
意味着转置4D阵列,使得现在的形状是第2、第3、第0和第1维度。含义,来自(84, 36, 210, 45)
->(210, 45, 84, 36)
。这里更清楚。
通过添加轴进行标准广播
标准的方法,更有用的方法,是向array a
添加2个维度。所以现在,两个阵列共享前两个维度进行广播。
c = a[..., None, None] + b #(84,26,1,1) + (84, 36, 210, 45)
c.shape
(84, 36, 210, 45)
为了在这里澄清,a[..., None, None]
添加了2个新轴,并将形状为(84, 26)
的2D张量转换为形状为(84,26,1,1)
的4D张量。这里更清楚。
最后,为了证明这两种方法是等价的,你可以这样检查-
np.all((b.transpose(2,3,0,1) + a).transpose(2,3,0,1) == a[...,None, None] + b)
True
大型阵列的基准测试-
- 转座子法-1.88 s±977 ms/循环(7次运行的平均值±标准偏差,每次1个循环(
- 标准广播-每个循环1.25 s±156 ms(7次运行的平均值±标准偏差,每个循环1次(
然而,我注意到一件有趣的事情-当广播维度很大时,使用标准方法可以获得更好的加速。但当
b
的非广播维度较大时,转置方法似乎比简单广播快一点!我会对此进行一些分析并更新我的答案,但我肯定在这里找到了一些新的东西可以学习:(
哪一个更好
我遇到过一些情况,由于问题的性质,有必要同时使用两种方法(例如,在这种情况下,我需要同时使用这两种方法(。然而,我建议专注于标准方法,因为它的通用性要高得多。我将在稍后的编辑中尝试评论两者的表现。
In [340]: x = np.ones((3,4));
In [341]: x = np.ones((3,4))
In [342]: y = np.ones((3,4,2,2))
正在尝试可广播操作:
In [343]: x+y
Traceback (most recent call last):
File "<ipython-input-343-259706549f3d>", line 1, in <module>
x+y
ValueError: operands could not be broadcast together with shapes (3,4) (3,4,2,2)
broadcasting
可以将(3,4(的维度添加为(1,1,3,4。但这些不起作用。
相反,我们需要将维度添加到x
:
In [344]: x[:,:,None,None].shape
Out[344]: (3, 4, 1, 1)
现在它与(3,4,2,2(一起工作:
In [346]: c=x[:,:,None,None]+y
In [347]: c.shape
Out[347]: (3, 4, 2, 2)
阅读我评论中的广播文档。