在 Python 中的 NumPy 库中,**广播**(broadcasting)是一种用于在不同形状的数组间执行元素级运算的机制。广播允许我们在不显式复制数据的情况下执行计算,自动扩展数组的形状以匹配彼此,从而简化代码,提高运算效率。
### 广播规则
当 NumPy 尝试广播两个数组时,会遵循以下规则:
1. **从后往前比较维度**:
- 从两个数组的最后一个维度开始逐个比较,如果维度相同,或者其中一个维度是 1,则继续比较下一个维度。
2. **维度不兼容时自动扩展为相同形状**:
- 如果一个数组的维度为 1,而另一个数组的维度不同,则 NumPy 会将该维度的大小扩展为匹配的维度。
3. **广播成功条件**:
- 两个数组的维度要么相等,要么其中一个维度为 1,否则无法广播。
### 广播的例子
#### 例 1:标量与数组广播
```python
import numpy as np
a = np.array([1, 2, 3])
b = 2
result = a + b # 结果:[3, 4, 5]
```
这里 `b` 是标量,NumPy 自动将 `b` 扩展为 `[2, 2, 2]`,然后和 `a` 相加。
#### 例 2:一维数组和二维数组广播
```python
import numpy as np
a = np.array([1, 2, 3]) # 形状为 (3,)
b = np.array([[10], [20], [30]]) # 形状为 (3, 1)
result = a + b
# 结果:
# [[11, 12, 13],
# [21, 22, 23],
# [31, 32, 33]]
```
在这里,`a` 的形状是 `(3,)`,`b` 的形状是 `(3, 1)`。NumPy 会将 `a` 的形状扩展为 `(3, 3)`,将 `b` 的形状扩展为 `(3, 3)`,然后进行元素级相加。
#### 例 3:不同大小的二维数组广播
```python
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]]) # 形状为 (2, 3)
b = np.array([[10], [20]]) # 形状为 (2, 1)
result = a + b
# 结果:
# [[11, 12, 13],
# [24, 25, 26]]
```
这里 `a` 的形状是 `(2, 3)`,`b` 的形状是 `(2, 1)`。NumPy 会将 `b` 的形状扩展为 `(2, 3)`,然后逐元素相加。
#### 例 4:广播失败的情况
```python
import numpy as np
a = np.array([1, 2, 3]) # 形状为 (3,)
b = np.array([[1, 2], [3, 4]]) # 形状为 (2, 2)
# result = a + b # 报错:operands could not be broadcast together
```
在这种情况下,`a` 的形状是 `(3,)`,`b` 的形状是 `(2, 2)`。两者的维度不兼容,无法广播,因此运算失败。
在这个例子中,`a` 和 `b` 可以广播的原因是:
- **数组 `a` 的形状**是 `(2,)`。
- **数组 `b` 的形状**是 `(2, 2)`。
根据广播规则,**从后往前**比较两个数组的维度(并在需要时补齐前面的维度):
1. `a` 的形状 `(2,)` 可以理解为 `(1, 2)`,这样就和 `b` 的形状 `(2, 2)` 有了匹配的维度。
2. 按照广播规则,如果两个维度中的一个是 1,那么 NumPy 会将这个维度扩展到与另一数组的维度相同。
因此,`a` 会被扩展为形状 `(2, 2)`,具体扩展为:
```
a: [[1, 2],
[1, 2]]
```
此时 `a` 和 `b` 的形状匹配,就可以逐元素运算了。