NumPy 广播

2021-09-01 10:19 更新

术语广播描述了 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 足够聪明,可以使用原始标量值而无需实际制作副本,以便广播操作尽可能具有内存和计算效率。

第二个示例中的代码比第一个示例中的代码更高效,因为广播在乘法期间移动的内存更少(b是标量而不是数组)。

一般广播规则

在对两个数组进行操作时,NumPy 按元素比较它们的形状。它从尾随(即最右边)尺寸开始并向左工作。当两个维度兼容时

  1. 他们是平等的,或者
  2. 其中之一是 1

如果不满足这些条件, 则会抛出异常,表明数组具有不兼容的形状。结果数组的大小是沿着输入的每个轴不为 1 的大小。ValueError: operands could not be broadcast together 阵列不需要有相同数量的尺寸。例如,如果您有一个256x256x3RGB 值数组,并且您想用不同的值缩放图像中的每种颜色,您可以将图像乘以具有 3 个值的一维数组。根据广播规则排列这些数组的尾随轴的大小,表明它们是兼容的:

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

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

在以下示例中,AB数组都具有长度为 1 的轴,这些轴在广播操作期间扩展为更大的尺寸:

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.]])

广播提供了一种获取两个数组的外积(或任何其他外操作)的便捷方法。以下示例显示了两个一维数组的外加运算:

>>> 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,使其成为二维4x1数组。将4x1数组与b具有 shape 的 组合(3,)产生一个4x3数组。

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号