【问题标题】:Numpy, python: automatically expand dimensions of arrays when broadcastingNumpy,python:广播时自动扩展数组的维度
【发布时间】:2013-07-08 18:40:21
【问题描述】:

考虑下面的 Numpy 数组广播练习。

import numpy as np
v = np.array([[1.0, 2.0]]).T # column array

A2 = np.random.randn(2,10) # 2D array
A3 = np.random.randn(2,10,10) # 3D

v * A2 # works great

# causes error: 
v * A3 # error

我知道广播的 Numpy 规则,并且我熟悉 Matlab 中的bsxfun 功能。我理解为什么尝试将 (2,1) 数组广播到 (2,N,N) 数组会失败,并且在此之前我必须将 (2,1) 数组重新整形为 (2,1,1) 数组广播通过。

我的问题是:有没有办法告诉 Python 在尝试广播时自动填充数组的维数,而无需我专门告诉它必要的维数?

我不想明确地将 (2,1) 向量与将要广播的多维数组耦合——否则我可能会做一些愚蠢而丑陋的事情,比如 @987654324 @。我不知道“A”数组是 2D 还是 3D 还是 N-D。

Matlab 的 bsxfun 广播功能会根据需要隐式填充尺寸,所以我希望我可以在 Python 中做一些事情。

【问题讨论】:

  • 我的观点是这是一个特性而不是一个错误。例如,假设您有一个 2×1 列向量 v,然后您有一个 2×2×10 ndarray。您想将v 重塑为具有(2,1,1) 形状还是(1,2,1) 形状?如果您只是填充尺寸,则用户可能会模棱两可。强制显式整形是一个更好的通用过程,如果用户有固定的约定,则留给用户编写一个特殊的函数来自动执行整形。但是创建一个全局的 numpy 维度填充器是不好的,它会强制你遵守约定。太容易误用了。
  • -1 @EMS。通过指定将在广播中使用第一个非单一维度,可以轻松解决这种歧义。这种“这样更好”的态度完全不适合专业程序员和应用数学家使用的系统——这是难以辨认和复杂性方面的缺陷,而不是特性。
  • -1 @Ahmed Fasih。我是一名应用数学家,每天为科学应用程序编写 Python 代码,我觉得你提出的始终采用第一个非单维的约定会很糟糕。与 NumPy 开发人员担心硬编码这样的约定相比,您编写一个采用该约定的函数要好得多,这对某些用户(例如您)但对其他一些用户(例如我)没有用处。跨度>
  • 另外,尽管问题的开头不同,这可能与以下内容重复:stackoverflow.com/questions/15296944/… >。我认为numpy.apply_along_axis 和numpy.tensordot 尤其对于这种事情来说似乎绰绰有余,同时仍然保留了程序员必须明确提及广播时应该发生模糊维度变化的方式的好属性。
  • 我希望apply_along_axis 通过对数组操作进行去矢量化来完全破坏性能。此外,广播比通过tensordot 进行乘法更有用。

标签: python numpy multidimensional-array


【解决方案1】:

这很丑,但这会起作用:

(v.T * A3.T).T

如果你不给它任何参数,转置会反转形状元组,所以你现在可以依靠广播规则来发挥它们的魔力。最后的转置将所有内容恢复到正确的顺序。

【讨论】:

  • 它实际上没有我在研究@unutbu 的答案(np.swapaxes(v.T * np.swapaxes(A3,0,-1), 0, -1))后得到的那么丑!知道转置反转所有维度使得这更加整洁。至少用户会看到这些转置并希望认为“好吧,这里正在进行广播,只需一点点时髦就可以使尺寸对齐,好吧,我很好”。谢谢大佬。
【解决方案2】:

NumPy 广播在左侧添加了额外的轴。

因此,如果您排列数组,使共享轴在右侧,可广播轴在左侧,那么您可以毫无问题地使用广播:

import numpy as np
v = np.array([[1.0, 2.0]])  # shape (1, 2)

A2 = np.random.randn(10,2) # shape (10, 2)
A3 = np.random.randn(10,10,2) # shape (10, 10, 2)

v * A2  # shape (10, 2)

v * A3 # shape (10, 10, 2)

【讨论】:

  • 这至少是一个中途的解决方案。不幸的是,我的应用程序中的既定约定是像 v 这样的向量是列数组。假设我不想重新组织代码(和我的用户)以期望行数组,我正在争论交换维度以进行广播乘法的函数是否真的比交织 A 和 @ 的重塑操作更复杂987654324@ 在我的原始帖子中。
  • Numpy 在左侧添加维度而不是在右侧添加维度有什么原因吗?这似乎是武断的,但也许有一些与记忆或代数相关的重要理由?
  • 可能回答我自己的(子)问题,是因为广播从数组的尾随维度开始并向左工作,并根据需要不断添加维度,只要满足规则?有趣!
  • NumPy 数组默认采用 C 连续顺序(last-index 变化最快)。所以在左边添加额外的轴基本上是没有成本的——只有strides 和shape 属性必须改变,而基础数据可以保持不变。如果 NumPy 数组默认为 F 连续顺序,那么通过在右侧添加轴,广播将最自然地工作。
猜你喜欢
  • 1970-01-01
  • 2013-07-08
  • 1970-01-01
  • 1970-01-01
  • 2014-05-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-24
  • 1970-01-01
相关资源
最近更新 更多