NumPy实现广播机制与广播规则的示例
作者:MediaTea
在 NumPy 中,广播(Broadcasting)是一组形状匹配规则,用于支持逐元素运算在不同形状数组之间自动对齐,从而在不编写 Python 循环、不显式复制数据的前提下,实现高效的向量化计算。
一、什么是广播?
我们知道,当两个数组形状相同,二元运算会逐元素执行:
import numpy as np a = np.array([0, 1, 2])b = np.array([5, 5, 5]) a + b
输出:array([5, 6, 7])
广播允许对不同形状的数组执行类似的逐元素运算。
例如,可以将一个标量(可以将其视为一个 0 维数组)加到数组上:
a + 5
输出:array([5, 6, 7])
可以将其理解为将数值 5 “拉伸”或“复制”为 [5, 5, 5] 后再进行相加。
但需要强调的是,NumPy 并不会创建 [5, 5, 5] 再相加,而是在计算过程中将标量“广播”到数组的每个元素。
这种机制不仅适用于标量,也适用于更高维的数组,只要满足一定规则。
观察一维数组与二维数组相加的结果:
M = np.ones((3, 3))M
输出:array([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]])
再执行:
M + a
输出:array([[1., 2., 3.], [1., 2., 3.], [1., 2., 3.]])
此处,一维数组 a 被“拉伸”或广播到第二个维度,以匹配 M 的形状。
这些示例较为直观。但在更复杂的情况下,两个数组都可能发生广播。请看下例:
a = np.arange(3)b = np.arange(3)[:, np.newaxis] print(a)print(b)
输出:[0 1 2][[0] [1] [2]]
当执行:a + b
输出:array([[0, 1, 2], [1, 2, 3], [2, 3, 4]])
正如前述例子中将一个值“拉伸”以匹配另一个数组的形状一样,在这里,a 和 b 都被“拉伸”到一个共同形状,结果是一个二维数组。
下图展示了这些示例的几何结构。

浅色区域表示被广播的值。再次强调,这些额外内存在实际计算中并未真正分配,但在概念上进行这样的想象有助于理解什么是“广播”。
要注意的是,广播只发生在:
- 逐元素 ufunc
- 运算符重载运算
不会发生在:
- 矩阵乘法 @ 和 matmul
- 点积 dot
二、广播规则
NumPy 中的广播遵循一套严格规则和步骤来确定两个数组之间如何交互。
广播比较是从最后一维(尾维)开始对齐,正确广播后的结果形状等于“各维度取最大值”。
- 规则 1:如果两个数组的维度数不同,则在维度较少的数组形状左侧补 1。
- 规则 2: 若在某一维上(从最后一维开始)两个数组的形状不相同,则该维度中长度等于 1 的数组会被扩展至与另一数组匹配。
- 规则 3: 如果在任意维度上两个数组的大小不同,且长度都不等于 1,则抛出错误。
下面通过具体示例说明。
广播示例 1:将二维数组与一维数组相加
M = np.ones((2, 3))a = np.arange(3)
数组形状为:
M.shape = (2, 3)a.shape = (3,)
根据规则 1,对 a 的形状左侧补 1:
M.shape -> (2, 3)a.shape -> (1, 3)
根据规则 2,第一维不一致,因此将其扩展:
M.shape -> (2, 3)a.shape -> (2, 3)
形状匹配,结果形状为 (2, 3):
M + a
输出:array([[1., 2., 3.], [1., 2., 3.]])
广播示例 2:两个数组都需要广播
a = np.arange(3).reshape((3, 1))b = np.arange(3)
形状:
a.shape = (3, 1)b.shape = (3,)
首先按照规则 1,数组 b 的形状左侧补 1:
a.shape -> (3, 1)b.shape -> (1, 3)
然后按照规则 2,先后扩展数组 a 的形状和数组 b 的形状:
a.shape -> (3, 3)b.shape -> (3, 3)
由于最终形状一致,因此这两个数组的形状是兼容的。下面可以看到这一点:
a + b
输出:array([[0, 1, 2], [1, 2, 3], [2, 3, 4]])
广播示例 3:不兼容的情形
M = np.ones((3, 2))a = np.arange(3)
形状:
M.shape = (3, 2)a.shape = (3,)
首先按照规则 1,数组 a 的形状左侧补 1:
M.shape -> (3, 2)a.shape -> (1, 3)
然后按照规则 2,第二维比较时发现 2 ≠ 3 且均不为 1,此时触发规则 3,最终形状不一致,因此不兼容。
当执行:
M + a
会产生:ValueError: operands could not be broadcast together with shapes (3,2) (3,)
需要注意的是,不能假设右侧补 1。广播规则只允许在左侧补 1。若需要右侧补 1,必须显式 reshape:
a.reshape(3, 1)# (3, 1)
或者:
a[:, np.newaxis]# 等价于a[:, None]
当执行:
M + a[:, np.newaxis]
输出:array([[1., 1.], [2., 2.], [3., 3.]])
广播规则适用于所有二元通用函数(ufunc)。例如:
np.logaddexp(M, a[:, np.newaxis])
array([[1.31326169, 1.31326169], [1.69314718, 1.69314718], [2.31326169, 2.31326169]])
logaddexp(x, y) 计算 log(exp(x) + exp(y)),并以更高数值精度实现。
三、NumPy 广播的实际应用
1、数据中心化
假设有 10 条观测数据,每条包含 3 个特征,存储为 10×3 数组:
X = np.random.random((10, 3))
计算每个特征的均值:
Xmean = X.mean(0)# array([0.56171119, 0.37035172, 0.56328698])
中心化数据:
X_centered = X - Xmean
验证均值是否接近 0:
X_centered.mean(0)# array([ 5.55111512e-17, -4.44089210e-17, -7.77156117e-17])
结果在机器精度范围内接近 0。
2、绘制二维函数
广播在生成二维函数图像时非常有用。
x = np.linspace(0, 5, 50)y = np.linspace(0, 5, 50)[:, np.newaxis] z = np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
x 与 y 自动广播生成 50×50 网格。
使用 Matplotlib 可视化:
import matplotlib.pyplot as plt plt.imshow(z, origin='lower', extent=[0, 5, 0, 5], cmap='viridis')plt.colorbar()

广播使二维函数的计算无需显式双重循环。
小结
广播是一组严格规则,用于支持不同形状数组之间的逐元素运算:
- 维度不足时在左侧补 1
- 从右向左逐维比较,每一维必须“相等或存在 1”
- 不满足条件则报错
广播机制是 NumPy 向量化计算的重要基础,广泛应用于科学计算、机器学习与数据分析中。
到此这篇关于NumPy实现广播机制与广播规则的示例的文章就介绍到这了,更多相关NumPy 广播机制与广播规则内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
