数组广播
广播, broadcast, 是NumPy对不同形状的数据进行计算时采取的兼容措施.
目的
两个数组形状相同
NumPy操作通常在成对的数组上逐元素进行. 在最简单的情况下, 这两个数组必须具有完全相同的形状(维度相同, 每一维度上的大小相同).
例子
两个数组形状不同
NumPy的广播机制在两个数组的形状满足一定要求时放松了对"具有完全相同的形状才能进行操作"的限制.
例子
这个结果和之前b
是一个数组的时候相同. 我们可以想象标量b
在算数运算时被延生成了一个和a
形状相同的数组. 产生的数组中的元素是原标量b
的副本. 这个延生的类比只是形式上的, 在实际内部, NumPy非常智能, 能够不创建延生数组而直接使用原始的标量b
, 这会使广播占用较小的内存提高效率.
实际上, 这个例子中的运算比上个例子中的计算效率更高. 因为使用广播机制使得这个例子效率更高移动了更少的内存.
解释图:
广播规则
对于两个数组形状不同的情况, 要想使用广播, 这两个形状应当符合一定的要求.
笔记
我们将形状中的每一个维度称为该维度的大小.
NumPy会从右到左逐个维度地比较两个维度的大小. 这两个维度是兼容的如果:
- 相等
- 其中一个是1
注意
- 两个数组的维度不一定要相同, 结果数组的维度和输入的两个数组中最大的维度相等, 结果数组中每个维度的大小和输入的两个数组中对应维度的最大大小相等. 缺失的维度大小被假设为1.
- 如果上述地条件没有被满足, 则会抛出
ValueError: operands could not be broadcase together
错误, 表示无法进行广播, 即无法对两个数组进行操作.
例子
定义:
流程:
-
缺失的维度大小假设为
1
-
从右到左比较每一个维度
- 最右边的维度:
3
和3
, 相等, 兼容 - 中间的维度:
256
和1
, 其中一个是1, 兼容 - 最左边的维度:
256
和1
, 其中一个是1, 兼容
这表示可以广播, 正确返回结果数组
- 最右边的维度:
-
结果数组的维度和输入的两个数组中最大的维度相等, 结果数组中每个维度的大小和输入的两个数组中对应维度的最大大小相等. 执行广播返回结果数组
定义:
流程:
-
缺失的维度大小假设为
1
-
从右到左比较每一个维度
- 最右边的维度:
1
和5
, 其中一个是1, 兼容 - 次右边的维度:
6
和1
, 其中一个是1, 兼容 - 次左边的维度:
1
和7
, 其中一个是1, 兼容 - 最左边的维度:
8
和1
, 其中一个是1, 兼容
这表示可以广播, 正确返回结果数组
- 最右边的维度:
-
结果数组的维度和输入的两个数组中最大的维度相等, 结果数组中每个维度的大小和输入的两个数组中对应维度的最大大小相等. 执行广播返回结果数组
定义:
流程:
-
缺失的维度大小假设为
1
-
从右到左比较每一个维度
- 最右边的维度:
256
和3
, 不兼容 - 中间的维度:
256
和1
, 其中一个是1, 兼容 - 最左边的维度:
256
和1
, 其中一个是1, 兼容
这表示不可以广播, 无法返回结果数组, 报错:
ValueError: operands could not be broadcast together
- 最右边的维度:
定义:
>>> a = np.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 = np.array([1.0, 2.0, 3.0])
>>> a + b
array([[ 1., 2., 3.],
[11., 12., 13.],
[21., 22., 23.],
[31., 32., 33.]])
>>> b = np.array([1.0, 2.0, 3.0, 4.0])
>>> a + b
Traceback (most recent call last):
ValueError: operands could not be broadcast together with shapes (4,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.]])
关于a[:, np.newaxis]
用于将一维行向量转为列向量, 详情见这里
原理图:
上述规则不但对两个数组适用, 如果一堆数组两两都符合上述规则, 则称这堆数组称为"可广播".
例子
假设有a, b, c, d
四个数组, 它们的形状为:
a
:(5, 1)
b
:(1, 6)
c
:(6, )
d
:()
, 注意b
是标量, 但介于NumPy中标量和向量的一致性, 我们将其视为一个数组
假设它们的值为:
>>> a
array([[1],
[2],
[3],
[4],
[5]])
>>> b
array([[1, 2, 3, 4, 5, 6]])
>>> c
array([1, 2, 3, 4, 5, 6])
>>> d
1
(5, 6)
. 详细解释广播的过程:
-
a
的低维被广播, 变成: -
b
的高维被广播, 变成: -
c
缺失的维度的大小被假设为1, 所以情况和b
类似, 变成: -
d
缺失的维度的大小被假设为1, 重复单一的值, 变成:
-
Broadcasting—NumPy v2.0 Manual. (n.d.). Retrieved June 22, 2024, from https://numpy.org/doc/stable/user/basics.broadcasting.html ↩
-
NumPy 广播(Broadcast) | 菜鸟教程. (n.d.). Retrieved June 22, 2024, from https://www.runoob.com/numpy/numpy-broadcast.html ↩