阵列广播

让我们探索一个更先进的概念,在numpy称为广播。术语广播描述了numpy如何在算术运算中处理不同形状的数组。受某些限制,较小的数组在较大的数组中“广播”,以便它们具有兼容的形状。广播提供了一种向量化数组操作的方法,以便循环在C中而不是在Python中发生。它可以在不进行不必要的数据复制的情况下做到这一点,并且通常会导致高效的算法实现。有些情况下,广播是个坏主意,因为它会导致内存使用效率低下,从而减慢计算速度。本文通过从简单到复杂的许多例子对广播进行了温和的介绍。它还提供有关何时和何时不使用广播的提示。

numpy操作通常是逐元素执行的,这需要两个数组具有完全相同的形状:

例1
>>> from numpy import array
>>> a = array([1.0, 2.0, 3.0])
>>> b = array([2.0, 2.0, 2.0])
>>> a * b
array([ 2.,  4.,  6.])

当数组的形状满足某些约束时,numpy的广播规则会放宽此约束。最简单的广播示例是在操作中组合数组和标量值时发生的:

例2
>>> from numpy import array
>>> a = array([1.0,2.0,3.0])
>>> b = 2.0
>>> a * b
array([ 2.,  4.,  6.])

结果与前面的示例等效,其中 b 是一个数组。我们可以想到标量 b 在算术运算过程中被拉伸成与 a . 中的新元素 b ,如图所示 图1 ,只是原始标量的副本。拉伸类比只是概念上的。numpy足够聪明,可以使用原始的标量值,而不需要实际制作副本,因此广播操作的内存和计算效率尽可能高。因为 例2 移动更少的内存, (b 是一个标量,而不是数组)在乘法过程中,它比 例1 在Windows2000上使用带有一百万个元素数组的标准numpy。

Vector-Scalar multiplication

图1

In the simplest example of broadcasting, the scalar ``b`` is stretched to become an array of same shape as ``a`` so the shapes are compatible for element-by-element multiplication.

两个数组是否具有可用于广播的兼容形状的规则可以用一句话来表示。

广播规则

为了广播,一个操作中两个数组的尾随轴的大小必须相同,或者其中一个必须是一个。

如果不满足此条件,则 ValueError('frames are not aligned') 引发异常,指示数组具有不兼容的形状。广播操作创建的结果数组的大小是输入数组中每个维度的最大大小。请注意,该规则没有说明需要具有相同数量维度的两个数组。因此,例如,如果您有一个256 x 256 x 3的RGB值数组,并且您希望用不同的值缩放图像中的每种颜色,那么您可以用一个一维数组将图像乘以3个值。根据广播规则排列这些阵列的尾随轴的大小,表明它们是兼容的。

图像

(3D阵列)

256 X

256 X

3

规模

(一维数组)

3

结果

(3D阵列)

256 X

256 X

3

在下面的示例中,两个 AB 数组有长度为1的轴,在广播操作中扩展到更大的尺寸。

A

(4D阵列)

8 X

1 X

6 X

1

B

(3D阵列)

7 X

1 X

5

结果

(4D阵列)

8 X

7 X

6 X

5

下面是一些代码示例和图形表示,它们有助于使广播规则在视觉上变得明显。 例3 将一维数组添加到二维数组:

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

如图所示 图2b 添加到每行 a . 什么时候? ba ,如 图3 ,由于形状不兼容,引发异常。

Matrix-Vector

图2

A two dimensional array multiplied by a one dimensional array results in broadcasting if number of 1-d array elements matches the number of 2-d array columns.

Matrix-Vector-with-error

图3

When the trailing dimensions of the arrays are unequal, broadcasting fails because it is impossible to align the values in the rows of the 1st array with the elements of the 2nd arrays for element-by-element addition.

广播提供了获取两个阵列的外部产品(或任何其他外部操作)的方便方法。下面的示例显示两个一维数组的外部加法运算,其结果与 例3

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

在这里,new axis索引运算符将新轴插入 a 使其成为二维4x1阵列。 图4 演示了两个阵列的拉伸以生成所需的4x3输出阵列。

vector-vector with newaxis

图4

在某些情况下,广播会拉伸两个数组,以形成比任何初始数组都大的输出数组。*

一个实际的例子:矢量量化。

广播在现实生活中经常出现问题。在信息理论、分类和其他相关领域中,矢量量化(VQ)算法就是一个典型的例子。VQ中的基本操作 [#f0] finds the closest point in a set of points, called codes in VQ jargon, to a given point, called the observation. In the very simple, two-dimensional case shown in 图5, the values in observation describe the weight and height of an athlete to be classified. The codes represent different classes of athletes. 2 要找到最近的点,需要计算观测值和每个代码之间的距离。最短的距离提供最佳匹配。在这个例子中, codes[0] 最接近的等级表示运动员可能是篮球运动员。

vector quantitization example

图5

矢量量化的基本运算是计算被分类物体与暗正方形之间的距离,以及多个已知代码之间的距离,即灰色圆圈。在这个简单的例子中,代码代表单个类。更复杂的情况是每个类使用多个代码。

脚注

1

矢量量化J.Makhoul,S.Roucos和H.Gish,“语音编码中的矢量量化”,过程。IEEE,第73卷,1551-1587页,1985年11月。

2

在本例中,由于较大的值,重量对距离计算的影响大于高度。在实际应用中,高度和重量的标准化非常重要,通常是通过数据集之间的标准偏差来实现的,从而使两者对距离计算的影响相等。

注解

产生数字的代码是 AstroML book