我有带有多维数组的脚本,而不是 for 循环,我想使用矢量化实现来解决我的问题(有时包含列操作)。

让我们考虑一个带有矩阵 arr 的简单示例:

> arr = np.arange(12).reshape(3, 4)

> arr
> ([[ 0,  1,  2,  3],
    [ 4,  5,  6,  7],
    [ 8,  9, 10, 11]])

> arr.shape
> (3, 4)

所以我们有一个 3 行 4 列的矩阵 arr

我的脚本中最简单的情况是 添加到数组中的值。例如。我正在为单个或多个 执行此操作:
> someVector = np.array([1, 2, 3, 4])
> arr[0] += someVector

> arr
> array([[ 1,  3,  5,  7],    <--- successfully added someVector
         [ 4,  5,  6,  7],         to one row
         [ 8,  9, 10, 11]])

> arr[0:2] += someVector

> arr
> array([[ 2,  5,  8, 11],    <--- added someVector to two
         [ 5,  7,  9, 11],    <--- rows at once
         [ 8,  9, 10, 11]])

这很好用。但是,有时我需要操作一个或多个 。一次一列有效:
> arr[:, 0] += [1, 2, 3]

> array([[ 3,  5,  8, 11],
         [ 7,  7,  9, 11],
         [11,  9, 10, 11]])
           ^
           |___ added the values [1, 2, 3] successfully to
                this column

但我正在努力思考为什么这个 不能同时用于 多列的 :
> arr[:, 0:2] += [1, 2, 3]

> ValueError
> Traceback (most recent call last)
> <ipython-input-16-5feef53e53af> in <module>()
> ----> 1 arr[:, 0:2] += [1, 2, 3]

> ValueError: operands could not be broadcast
>             together with shapes (3,2) (3,) (3,2)

这不是与 的工作方式完全相同吗?我在这里做错了什么?

最佳答案

要将一维数组添加到多列,您需要将值 broadcast 到二维数组。由于默认情况下广播会在(形状的)左侧添加新轴,因此会自动将行向量广播到多行:

arr[0:2] += someVector
someVector 的形状为 (N,) 并被自动广播为形状 (1, N) 。如果 arr[0:2] 的形状为 (2, N) ,则按元素执行求和,就好像 arr[0:2]someVector 都是相同形状 (2, N) 的数组。

但是要将列向量广播到多列需要提示 NumPy 您希望广播发生在右侧的轴上。实际上,您必须使用 someVector[:, np.newaxis] 或等效的 someVector[:, None] 在右侧显式添加新轴:
In [41]: arr = np.arange(12).reshape(3, 4)

In [42]: arr[:, 0:2] += np.array([1, 2, 3])[:, None]

In [43]: arr
Out[43]:
array([[ 1,  2,  2,  3],
       [ 6,  7,  6,  7],
       [11, 12, 10, 11]])
someVector(例如 np.array([1, 2, 3]) )的形状为 (N,)someVector[:, None] 的形状为 (N, 1) 所以现在广播发生在右侧。如果 arr[:, 0:2] 的形状为 (N, 2) ,则按元素执行求和,就好像 arr[:, 0:2]someVector[:, None] 都是相同形状 (N, 2) 的数组。

10-06 05:27