python列表+空numpy数组=空numpy数组?

时间:2019-11-14 10:33:19

标签: python arrays numpy numpy-broadcasting

今天,我发现我的代码有些奇怪,发现在某些情况下它会执行以下代码:

my_list = [0] + np.array([])

这导致my_list为以下内容:

array([], dtype=float64)

一开始我很困惑,比我理解的解释器要先将列表转换成一个numpy数组,然后再尝试广播操作:

>>> np.array([0]) + np.array([])
array([], dtype=float64)

我对此行为有疑问:

  • 为什么要广播?
  • 如果python抛出一个 错误,至少对于转换和创建列表的特定情况 消失吗?

感谢您的澄清!

1 个答案:

答案 0 :(得分:3)

首先:

  

如果python抛出错误,至少在这种情况下,列表会转换并消失,这会更好吗?

我认为不可能进行测试。根据{{​​3}}:

  

对于像b.__radd__(a)这样的反向操作,我们称为相应的ufunc。

这意味着使用[0] + np.array([])实际上会调用ufunc np.add([0], np.array([])),它将类似数组的列表转换为数组,而没有机会决定操作数的大小。

所以广播是必然的。问题是,将形状(1,)(0,)广播到(0,)是否理智。您可以这样考虑:标量总是广播,在大多数情况下1元素1d数组与标量一样好:

>>> np.add([0], [])
array([], dtype=float64)

>>> np.add(0, [])
array([], dtype=float64)

如果您以这种方式看待它,通常来说还是有道理的,尽管我同意这是令人惊讶的,尤其是非长度数组不会像这样广播。但这不是错误(对于功能而言只是一种有趣的情况)。


更确切地说,广播所发生的总是“尺寸为1的尺寸将广播”。类似于数组的[0]的形状为(1,)np.array([])的形状为(0,)(与标量np.int64()的形状为{{1}相对) }!)。因此广播是在单例上发生的,结果的形状为()

如果我们注入更多的单例尺寸,它将变得更加清晰:

(0,)

例如,在最后一种情况下,形状>>> ([0] + np.array([])).shape (0,) >>> ([[0]] + np.array([])).shape (1, 0) >>> ([[[0]]] + np.array([])).shape (1, 1, 0) >>> np.shape([[[0]]]) (1, 1, 1) 将沿其最后一个维度很好地以1d数组进行广播,在这种情况下,结果的确应该为(1, 1, 1)