首页 > 解决方案 > 在形状()和(1,)之间,为什么我可以执行常规但不能就地操作?

问题描述

当我尝试从形状(1,)到形状()进行就地广播时,numpy raises ValueError: non-broadcastable output operand with shape () doesn't match the broadcast shape (1,)。我知道就地运算符旨在与 input 对同一块内存进行操作,这就是为什么您不能从形状 (5,) 就地广播到形状 (1,) 的原因。但在形状 (1,) (或任何大小为 1 的数组)的情况下,大小与形状 () 的标量相同。那为什么我不能a += ba有 shape()b有 shape的地方执行就地操作(1,)?反之亦然。_

代码:

a = np.array(0)
b = np.array([0])
a + b  # valid
b += a  # valid
a += b  # ValueError

结果:

ValueError: non-broadcastable output operand with shape () doesn't match the broadcast shape (1,)

标签: pythonnumpyarray-broadcastingin-place

解决方案


虽然我们可以从测试中获得一些想法,但它可能归结为实现细节(在编译代码中)。

In [81]: a = np.array(0); b = np.array([0])
In [82]: a,b
Out[82]: (array(0), array([0]))

两者之和产生一个 (1,) 数组。这符合广播规则。 a被广播到 (1,) 然后相加。

In [83]: a+b
Out[83]: array([0])

我们可以添加 () 或标量:

In [84]: a += a

但是您的错误案例显然是试图将此 (1,) 和放入 () 目标中:

In [85]: a += b
Traceback (most recent call last):
  File "<ipython-input-85-294cacd62d6f>", line 1, in <module>
    a += b
ValueError: non-broadcastable output operand with shape () doesn't match the broadcast shape (1,)

可以使用正确的索引为 赋值a

In [86]: a[:] = 1
Traceback (most recent call last):
  File "<ipython-input-86-aa15caba710a>", line 1, in <module>
    a[:] = 1
IndexError: too many indices for array: array is 0-dimensional, but 1 were indexed

In [87]: a[()] =2
In [88]: a
Out[88]: array(2)
In [89]: a[...] = a+b
In [90]: a
Out[90]: array(2)

但显然+=这种分配确实使用了这种更通用的分配方法。

我们也不能将+=(1,1) 变成 (1,):

In [92]: b += np.array([[1]])
Traceback (most recent call last):
  File "<ipython-input-92-15b525996e5d>", line 1, in <module>
    b += np.array([[1]])
ValueError: non-broadcastable output operand with shape (1,) doesn't match the broadcast shape (1,1)

显然+=,一种分配不能减少数字维度。

作为旁注,可以将 (1,) 数组广播到 (0,)

In [100]: c = np.zeros((0,))
In [101]: c += b
In [102]: c
Out[102]: array([], dtype=float64)

也就是说,在第二个广播步骤中(匹配维度数之后),它可以将大小 1 维度减少为 0。但这与将维度数从 更改为n+1不同n


推荐阅读