首页 > 解决方案 > 使用 np.transpose 使数组广播

问题描述

我有一个广播错误,如下所示:

ValueError:操作数无法与形状一起广播 (84,36) (84,36,210,45)

有没有办法解决这个问题?我尝试使用 np.transpose() 来移动索引,以便遵守广播规则,但不知何故,我得到的答案不再正确。np.transpose() 在这里真正做了什么?

标签: pythonnumpytransposearray-broadcasting

解决方案


您可以通过多种方式进行广播。

使用转置

较长的方式是您尝试使用的方式transpose。在这里,由于array a只有 2 个维度(它是最后 2 个维度),因此您也将 的前 2 个维度设置array b为最后 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)这里更清楚。


通过添加轴进行标准广播

更有用的一种标准方法是将 2 维添加到array a. 所以现在,这两个数组共享前两个用于广播的维度。

c = a[..., None, None] + b #(84,26,1,1) + (84, 36, 210, 45)
c.shape
(84, 36, 210, 45)

在这里澄清一下,a[..., None, None]添加 2 个新轴并将 shape 的 2D 张量转换为 shape(84, 26)的 4D 张量(84,26,1,1)这里更清楚。

最后,为了证明这两种方法是等效的,您可以像这样检查 -

np.all((b.transpose(2,3,0,1) + a).transpose(2,3,0,1) == a[...,None, None] + b)
True

大型阵列的基准测试 -

  1. 转置方法- 每个循环 1.88 秒 ± 977 毫秒(平均值 ± 标准偏差。7 次运行,每个循环 1 个)
  2. 标准广播- 每个循环 1.25 秒 ± 156 毫秒(平均值 ± 标准偏差。7 次运行,每个循环 1 个)

但是,我注意到一件有趣的事情 - 当广播维度很大时,使用标准方法可以获得更好的加速。但是当非广播维度的大小较大时b,转置方法似乎比简单广播要快一点!我会对此进行一些分析并更新我的答案,但我肯定在这里发现了一些新东西要学习:)

哪一个更好?

我遇到过一些情况,由于问题的性质,有必要同时使用这两种方法(例如,在这个赏金中,我需要同时使用这两种方法)。但是,我建议将重点放在标准方法上,因为它的用途要广泛得多。我将尝试在以后的编辑中评论两者的表现。


推荐阅读