【问题标题】:Numpy broadcasting sliced arrays and vectorsNumpy 广播切片数组和向量
【发布时间】:2014-04-06 21:13:42
【问题描述】:

给定三个 numpy 数组:一个多维数组 x,一个向量 y 带有尾随单维,一个向量 z 没有尾随单维,

x = np.zeros((M,N))
y = np.zeros((M,1))
z = np.zeros((M,))

广播操作的行为取决于向量表示和上下文:

x[:,0] = y      # error cannot broadcast from shape (M,1) into shape (M)
x[:,0] = z      # OK

x[:,0] += y     # error non-broadcastable output with shape (M) doesn't match 
                # broadcast shape(M,M)
x[:,0] += z     # OK

x - y           # OK
x - z           # error cannot broadcast from shape (M,N) into shape (M)

我意识到我可以做到以下几点:

x - z[:,None]   # OK

但我不明白这个明确的符号能给我带来什么。它当然不会购买可读性。我不明白为什么表达式x - y 是可以的,但x - z 是模棱两可的。

为什么 Numpy 会以不同的方式处理带有或不带有尾随单维的向量?

编辑:documentation 声明:两个维度在它们相等或其中之一为 1 时是兼容的,但 yz 在功能上都是 M x 1 向量,因为M x 0 向量不包含任何元素。

【问题讨论】:

  • 一个关键点是x[:,0]是1d。 x[:,[0]] 是 (M,1)。 z[:]=y 可能会给出同样的错误。
  • z 可以在不复制的情况下重塑为 (M,1) 或 (1,M)。但在功能上它更接近 (1,M),因为开头是自动扩展的。

标签: python numpy


【解决方案1】:

约定是广播将在数组形状的开头插入单个维度。这使得在数组的最后一个维度上执行操作变得很方便,所以(x.T - z).T 应该可以工作。

如果要自动决定x 的哪个轴与z 匹配,则像x - z 这样的操作将在且仅当N == M 时才会导致错误,从而使代码更难测试。因此,该约定提供了一些便利,同时对某些错误具有鲁棒性。

如果您不喜欢 z[:, None] 的简写,也许您会发现 z[:, np.newaxis] 更清晰。

对于像x[:,0] = y 这样的作业,您可以改用x[:,0:1] = y

【讨论】:

  • 你能举个例子说明在什么地方前置单例维度是有用的吗?我想要执行的一个常见操作是从矩阵中减去列均值,但最直观的方法 x -= np.mean(x, axis=1) 实际上并没有像人们希望的那样工作。
【解决方案2】:

使用 Numpy ma​​trix 接口而不是数组接口产生desired broadcasting behaviours

x = np.asmatrix(np.zeros((M,N)))
y = np.asmatrix(np.zeros((M,1)))

x[:,0] = y              # OK
x[:,0] = y[:,0]         # OK
x[:,0] = y[:,0:1]       # OK
x[:,0] += y             # OK
x - y                   # OK
x - np.mean(x, axis=0)  # OK
x - np.mean(x, axis=1)  # OK

【讨论】:

  • 另一方面,引入了各种其他问题。矩阵几乎总是难以发现错误的来源。例如,* 运算符执行矩阵乘法,而不是逐元素。如果你把它提供给一个需要数组的函数,你就完蛋了。
【解决方案3】:

区别对待(M,1)(M,) 的一个好处是让您能够指定要对齐的维度以及要广播的维度

假设你有:

a = np.arange(4)
b = np.arange(16).reshape(4,4)
# i.e a = array([0, 1, 2, 3])
# i.e b = array([[ 0,  1,  2,  3],
#   [ 4,  5,  6,  7],
#   [ 8,  9, 10, 11],
#   [12, 13, 14, 15]])

当您执行 c = a + b 时,ab 将在 axis=1 中对齐,a 将与 axis=0 一起广播:

array([[0, 1, 2, 3],
   [0, 1, 2, 3],
   [0, 1, 2, 3],
   [0, 1, 2, 3]])

但是如果你想在axis=0 中对齐ab 并在axis=1 中广播呢?

array([[0, 0, 0, 0],
   [1, 1, 1, 1],
   [2, 2, 2, 2],
   [3, 3, 3, 3]])

(M,1)(M,) 的差异使您可以指定要对齐和广播的维度。

(即如果(M,1)(M,) 被同等对待,你如何告诉numpy 你想在axis=1 上广播?)

【讨论】:

  • 我的错误在于从代数的角度来处理 numpy 数组,而不是作为通用容器。在您上面强调的情况下,c = a.T + bc = a + b 其中a.shape == (M,1) 将以一种对我来说直观的方式进行广播。这是我试图通过询问为什么在 numpy 的设计中做出特定决定来理解的哲学差异。感谢您的帮助!
  • 你是对的 2D a.T + b 可以指定广播首选项,但很难将其应用于更高维度的操作。我猜numpy的方法更通用。
猜你喜欢
  • 2015-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-10
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
相关资源
最近更新 更多