Python 中 NumPy 的广播

广播

广播描述了 NumPy 如何在算术运算期间处理具有不同形状的数组。为了实现形状兼容,较小的数组仍在较大的数组上“广播”。广播提供了一种矢量化数组操作的方法,以便在 C 而不是 Python 中进行循环。

NumPy 通常在逐个元素的基础上对数组对进行操作。在最简单的情况下,两个数组必须具有完全相同的形状,如:

>>> a = np.array([1.0, 2.0, 3.0])
>>> b = np.array([2.0, 2.0, 2.0])
>>> a * b
array([ 2.,  4.,  6.])

当数组的形状满足某些约束时,NumPy 的广播规放宽了这种约束。当一个数组和一个标量值在一个操作中组合时,会发生最简单的广播示例:

>>> a = np.array([1.0, 2.0, 3.0])
>>> b = 2.0
>>> a * b
array([ 2.,  4.,  6.])

结果等同于前面的示例,b 是数组。在算术运算期间,可以认为标量 b 被拉伸为和 a 具有相同形状的数组。新元素 b 只是原始标量的副本。实际过程中,NumPy 使用原始标量值而不创建副本,因此广播操作具有内存和计算效率。

一般广播规则

在两个数组上运行时,NumPy 会逐元素地比较它们的形状。它从尾部尺寸开始,并逐渐往前。两个尺寸兼容时有:

1. 形状相同

2. 其中一个是1

如果不满足这些条件,则抛出 ValueError: operands could not be broadcast together 异常,指示数组形状不兼容。结果数组的大小是输入数组每一维度的最大值。

数组不需要具有相同数量的维度。例如,如果您有一个 256*256*3 的RGB值数组,并且希望将图像中的每种颜色缩放不同的值,则可以将图像乘以具有 3 个值的一维数组。根据广播规则排列这些数组的尾轴的大小,表明它们是兼容的:

Image  (3d array): 256 x 256 x 3
Scale  (1d array):             3
Result (3d array): 256 x 256 x 3

当比较的任何一个尺寸为 1 时,使用另一个尺寸。换句话说,尺寸为 1 的尺寸被拉伸或“复制”以匹配另一个尺寸。

在以下示例中,A 和 B 数组都具有长度为 1 的轴,在广播操作期间会扩展为更大的大小:

扫描二维码关注公众号,回复: 9583794 查看本文章
A      (4d array):  8 x 1 x 6 x 1
B      (3d array):      7 x 1 x 5
Result (4d array):  8 x 7 x 6 x 5

以下是一些例子:

A      (2d array):  5 x 4
B      (1d array):      1
Result (2d array):  5 x 4

A      (2d array):  5 x 4
B      (1d array):      4
Result (2d array):  5 x 4

A      (3d array):  15 x 3 x 5
B      (3d array):  15 x 1 x 5
Result (3d array):  15 x 3 x 5

A      (3d array):  15 x 3 x 5
B      (2d array):       3 x 5
Result (3d array):  15 x 3 x 5

A      (3d array):  15 x 3 x 5
B      (2d array):       3 x 1
Result (3d array):  15 x 3 x 5

以下是不广播的形状示例:

A      (1d array):  3
B      (1d array):  4 # trailing dimensions do not match

A      (2d array):      2 x 1
B      (3d array):  8 x 4 x 3 # second from last dimensions mismatched

例子:

>>> x = np.arange(4)
>>> xx = x.reshape(4,1)
>>> y = np.ones(5)
>>> z = np.ones((3,4))

>>> x.shape
(4,)

>>> y.shape
(5,)

>>> x + y
ValueError: operands could not be broadcast together with shapes (4,) (5,)

>>> xx.shape
(4, 1)

>>> y.shape
(5,)

>>> (xx + y).shape
(4, 5)

>>> xx + y
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 2.,  2.,  2.,  2.,  2.],
       [ 3.,  3.,  3.,  3.,  3.],
       [ 4.,  4.,  4.,  4.,  4.]])

>>> x.shape
(4,)

>>> z.shape
(3, 4)

>>> (x + z).shape
(3, 4)

>>> x + z
array([[ 1.,  2.,  3.,  4.],
       [ 1.,  2.,  3.,  4.],
       [ 1.,  2.,  3.,  4.]])

广播提供了一种便捷的方式来获取两个数组的外积(或任何其他外部操作)。以下示例显示了两个 1-d 数组的外积操作:

>>> a = np.array([0.0, 10.0, 20.0, 30.0])
>>> b = np.array([1.0, 2.0, 3.0])
>>> a[:, np.newaxis] + b
array([[  1.,   2.,   3.],
       [ 11.,  12.,  13.],
       [ 21.,  22.,  23.],
       [ 31.,  32.,  33.]])

上边 newaxis 索引操作符插入一个新轴 a,使其成为一个二维 4*1 数组。将 4*1 数组与形状为 (3,) 的 b 组合,产生一个 4*3 数组。

参考资料:

1. NumPy 官方文档:https://numpy.org/devdocs/

发布了77 篇原创文章 · 获赞 5 · 访问量 4942

猜你喜欢

转载自blog.csdn.net/SAKURASANN/article/details/102654768