广播机制
In [1]: import numpy as np
在Numpy中,两个数组的相加、相减、相乘等操作时都是对应元素之间的操作:
In [2]: a=np.array([[1,2,3],[4,5,6]])
In [3]: b=np.array([[1,2,3],[4,5,6]])
In [4]: a+b
Out[4]:
array([[ 2, 4, 6],
[ 8, 10, 12]])
In [5]: a-b
Out[5]:
array([[0, 0, 0],
[0, 0, 0]])
In [6]: a*b
Out[6]:
array([[ 1, 4, 9],
[16, 25, 36]])
如果两个数组的形状不相同怎么办呢?
numpy的广播机制(broadcasting)旨在提供一种当被处理数组形状大小不一时仍然能计算的机制。它通过扩展数组的方法来实现不同形状的数组之间相加、相减、相乘等操作。
例如:
In [8]: a=np.array([1,2,3])
In [9]: b=2
In [10]: a*b
Out[10]: array([2, 4, 6])
图片来源[1]
In [11]: a=np.array([[0,0,0],[10,10,10],[20,20,20],[30,30,30]])
In [12]: b=np.array([1,2,3])
In [13]: a+b
Out[13]:
array([[ 1, 2, 3],
[11, 12, 13],
[21, 22, 23],
[31, 32, 33]])
图片来源[1]
In [14]: a=np.array([0,10,20,30])
In [15]: b=np.array([0,1,2])
In [16]: a[:,None]
Out[16]:
array([[ 0],
[10],
[20],
[30]])
In [17]: b
Out[17]: array([0, 1, 2])
In [18]: a[:,None]+b
Out[18]:
array([[ 0, 1, 2],
[10, 11, 12],
[20, 21, 22],
[30, 31, 32]])
图片来源[1]
In [32]: a=np.array([[0,0,0],[1,1,1],[2,2,2],[3,3,3]])
In [33]: b=np.array([1,2,3])
In [34]: a+b
Out[34]:
array([[1, 2, 3],
[2, 3, 4],
[3, 4, 5],
[4, 5, 6]])
图片来源 [2]
In [35]: a=np.array([[0,0,0],[1,1,1],[2,2,2],[3,3,3]])
In [36]: b=np.array([1,2,3,4])
In [37]: a
Out[37]:
array([[0, 0, 0],
[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
In [38]: b[:,None]
Out[38]:
array([[1],
[2],
[3],
[4]])
In [39]: a+b[:,None]
Out[39]:
array([[1, 1, 1],
[3, 3, 3],
[5, 5, 5],
[7, 7, 7]])
图片来源 [2]
In [46]: a=np.array([i for i in range(24)]).reshape((3,4,2))
In [47]: b=np.array([i for i in range(8)]).reshape((4,2))
In [48]: a
Out[48]:
array([[[ 0, 1],
[ 2, 3],
[ 4, 5],
[ 6, 7]],
[[ 8, 9],
[10, 11],
[12, 13],
[14, 15]],
[[16, 17],
[18, 19],
[20, 21],
[22, 23]]])
In [49]: b
Out[49]:
array([[0, 1],
[2, 3],
[4, 5],
[6, 7]])
In [50]: a+b
Out[50]:
array([[[ 0, 2],
[ 4, 6],
[ 8, 10],
[12, 14]],
[[ 8, 10],
[12, 14],
[16, 18],
[20, 22]],
[[16, 18],
[20, 22],
[24, 26],
[28, 30]]])
图片来源 [2]
但不是所有的数组之间都满足广播机制的条件,比如:
In [51]: a=np.array([[0,0,0],[10,10,10],[20,20,20],[30,30,30]])
In [52]: b=np.array([0,1,2,3])
In [53]: a+b
---------------------------------------------------------------------------
ValueError: operands could not be broadcast together with shapes (4,3) (4,)
图片来源 [1]
那么,广播机制的条件是什么呢?
对两个数组上进行运算时,NumPy会从最后一个维度开始,逐维度地比较它们的大小(不足的维度补1)。两个数组对应的维度需要满足两者相等或其中一个为1才可以进行广播,否则会报错。且计算结果每一维的尺寸为A,B对应维度尺寸的最大者。
以下是满足广播条件的例子[3]:A
与B
之间的运算
A (2d array): 5 x 4
B (1d array): 1
B (1d array): 1 x 1 # 补1
Result (2d array): 5 x 4
A (2d array): 5 x 4
B (1d array): 4
B (1d array): 1 x 4 # 补1
Result (2d array): 5 x 4
A (3d array): 15 x 3 x 5
B (3d array): 15 x 1 x 5
Result (3d array): 15 x 3 x 5
A (3d array): 15 x 3 x 5
B (2d array): 3 x 5
B (2d array): 1 x 3 x 5 # 补1
Result (3d array): 15 x 3 x 5
A (3d array): 15 x 3 x 5
B (2d array): 3 x 1
B (2d array): 1 x 3 x 1 # 补1
Result (3d array): 15 x 3 x 5
A (4d array): 8 x 1 x 6 x 1
B (3d array): 7 x 1 x 5
B (3d array): 1 x 7 x 1 x 5 # 补1
Result (4d array): 8 x 7 x 6 x 5
以下则是不满足广播条件的示例:
A (1d array): 2 x 3
B (1d array): 1 x 4 # 最后一个维度不符合条件
A (2d array): 2 x 1
B (3d array): 8 x 4 x 3 # 倒数第二个维度不符合条件
A (4d array): 8 x 2 x 6 x 1
B (3d array): 7 x 1 x 5 # 倒数第三个维度不符合条件
参考:
[1] https://numpy.org/devdocs/user/theory.broadcasting.html
[2] 《利用python进行数据分析》作者:Wes McKinney
[3]https://docs.scipy.org/doc/numpy-1.15.1/user/basics.broadcasting.html