1. 广播 broadcast是用来干什么的
首先,广播针对的运算是element wise类型的运算
element wise元素对元素类型的运算,这些运算的例子如下,在数学定义上要求必须满足相同位置的元素能一一对应,即相应维度的长度要相等/对齐(以下统称对齐)。
算数运算:+, -, *, /, //, %, divmod(), ** or pow(), <<, >>, &, ^, |
比较运算:==, <, >, <=, >=, !=
numpy中维度的对应顺序是倒着对应,两个数组倒数第一个维度相互对应,接着是倒数第二维,如此类推。element-wise的运算,当两个数组总维度不相同时,广播界定了是否能运算,能运算的话该按什么规则运算,厘清了这个场景下的计算规则问题。
例如下面的a和c对应维度对齐,但是总维度不同,该怎么算
"""
两个n-d数组维度相同时,element-wise运算怎么算很清晰
"""
a=np.random.randint(10, size=[2,5])
b=np.random.randint(10, size=[2,5])
(a+b).shape
Out: (2, 5)
"""
当两个n-d数组维度不相同,但看起来又“像能运算”,广播规则定义了该怎么计算
"""
c=np.random.randint(20, size=[2,2,5])
(a+c).shape
Out: (2, 2, 5) #广播定义了结果数组该怎么算出来
当两个n-d数组对应维度不对齐时,广播提供了一种处理规则:
在不对齐维度上,长度较短的自动做值复制来扩充长度,使得两个数组在该维度对齐,能进行合法运算。
(这种便利性是为了避免用户代码使用for循环操作数组的低效,自动扩充只是逻辑上的效果,实际上内部实现时是通过设置数组元素计算的step size为0实现的)
广播处理只对如下情况起作用:两个n-d数组,数组对应维度一个长度为m1=1,另一个长度m2>1,即 1 vs M的情况 (两个长度相等不用广播直接算)
广播内容:长度为1的维度会复制扩充为M个,这个维度完成对齐,接着重复检查上一层维度,如此反复,直至所有维度都检查完。
其他情况:当两个数组形状不是这种情况时(即此时相应维度一个数组长度m1>1,另一个长度m2>1,且m1≠m2),pyton直接报错,即此时不能运算,没有广播
如下图的例子,
1) 向量和标量运算,标量自动复制扩充为向量
2)矩阵和向量运算,向量在没对齐的维度自动复制扩充为矩阵
3)两个矩阵在两个维度上都不对齐,且都能广播,在每个维度上分别复制扩充
2. 例子
import numpy as np
a = np.array(
[[0, 1],
[2, 3],
[4, 5]])
b = np.array([10,20])
c = np.array([0, 1, 2])
"""
1. element-wise 运算,维度对应关系
b的第0维和a的第1维对齐(维度倒着对齐)
b重复和a的每行运算,输入结果为3*2维
"""
b*a
array([[ 0, 20],
[ 20, 60],
[ 40, 100]])
"""
1.1 相应维度不对齐,并且长度都不为1,非法
"""
c*a
ValueError: operands could not be broadcast together with shapes (3,) (3,2)
#c = np.array([0, 1, 2])
d=np.array([[10],[20],[30]])
"""
1.2 相应维度可广播
c在行方向复制扩充,d在列方向
"""
d+c
array([[10, 11, 12],
[20, 21, 22],
[30, 31, 32]])
"""
2.1 非element-wise运算,按运算定义来计算,基础对应维度上不适用广播
如果基础对应维度不对齐,会直接报错
"""
np.dot(d,c)
ValueError: shapes (3,1) and (3,) not aligned: 1 (dim 1) != 3 (dim 0)
#np.dot(c,d)是合法的
"""
2.2 非element-wise运算
基础维度合法对齐时,在更高维度上是element-wise对应的(以基础对应块为单位),会适用广播规则
"""
a=np.random.randint(24,size=[2,3,4])
b=np.random.randint(12,size=[4,2])
np.dot(a,b).shape #能合法进行运算
Out[111]: (2, 3, 2)