广播

广播是指NumPy在算术运算期间处理不同形状矩阵的能力。对矩阵的算术运算通常在相应的元素上进行,如果两个矩阵具有完全相同的形状,则算术操作会被直接执行。但是如果两个数组的维数不相同,则元素到元素的操作是不可能的。此时较小的数组会广播到较大数组的大小,以便形状可以兼容。

广播需要满足以下规则:

  • 维度较小的数组会在前面追加一个长度为1的维度。
  • 输出数组的每个维度的大小是输入数组该维度大小的最大值。
  • 如果输入在每个维度中的大小与输出大小匹配,或其值为1,则在计算中可广播。
  • 如果输入的某个维度大小为1,则该维度中的第一个数据将用于该维度的所有计算。

简而言之,如果两个数组从末尾开始算起的维度的轴长度相等,或者其中一方的长度为1,则它们是广播兼容的,广播会在缺失或者长度为1的轴上进行。

最简单的广播是一维数组与常量数字之间的运算,读者可在交互式解释器中试验以下示例来观察广播运算结果。

import numpy as np
arr = np.array([1, 2, 3])
arr += 4
print(arr)

在这个示例中,虽然执行的是运算: $$ \begin{bmatrix} 1 & 2 & 3 \end{bmatrix} + 4 = \begin{bmatrix} 5 & 6 & 7 \end{bmatrix} $$

NumPy实际上进行了以下运算: $$ \begin{bmatrix} 1 & 2 & 3 \end{bmatrix} + \begin{bmatrix} 4 & 4 & 4 \end{bmatrix} = \begin{bmatrix} 5 & 6 & 7 \end{bmatrix} $$

常量数字4被自动扩展成了一个长度为3的一维数组。

对于二维数组(矩阵)与一位数组相加的操作,则会出现以下效果: $$ \begin{bmatrix} 0 & 0 & 0 \\ 1 & 1 & 1 \\ 2 & 2 & 2 \\ 3 & 3 & 3 \end{bmatrix} + \begin{bmatrix} 1 & 2 & 3 \end{bmatrix} = \begin{bmatrix} 1 & 2 & 3 \\ 2 & 3 & 4 \\ 3 & 4 & 5 \\ 4 & 5 & 6 \end{bmatrix} $$

根据广播的原则,第一个数组的形状为\((4,3)\),第二个数组的形状为\((3,)\),所以会在较小的轴向上发生广播,一维数组\(\bigl[\begin{smallmatrix} 1 & 2 & 3\end{smallmatrix}\bigr]\)就被扩展为了\(\bigl[\begin{smallmatrix} 1 & 2 & 3 \\ 1 & 2 & 3 \\ 1 & 2 & 3 \\ 1 & 2 & 3 \end{smallmatrix}\bigr]\)。这样就可以完成形状不同的矩阵之间的运算了,对于更高维度的数组的计算,也同样适用于这个原则。

对于在多个轴向上进行广播的情形,例如: $$ \begin{bmatrix} 0 \\ 1 \\ 2 \\ 3 \end{bmatrix} + \begin{bmatrix} 1 & 2 & 3 \end{bmatrix} = \begin{bmatrix} 1 & 2 & 3 \\ 2 & 3 & 4 \\ 3 & 4 & 5 \\ 4 & 5 & 6 \end{bmatrix} $$

读者可自行在交互式解释器中进行试验来观察广播的操作规律。