广播的原则:
如果两个数组的后缘维度(从末尾开始算起的维度)的轴长度相符或其中一方的长度为1,则认为他们是广播兼容的。广播会在缺失和(或)长度为1的维度长进行。
看几个例子理解一下:
In [223]: arr = np.arange(4)
In [224]: arr
Out[224]: array([0, 1, 2, 3])
In [225]: arr*3 # 比较简单的广播的例子
Out[225]: array([0, 3, 6, 9])
低维度的值可以被广播到数组的任意维度:
In [226]: arr = np.array([[1],[2],[3]]) In [227]: arr Out[227]: array([[1],[2],[3]]) In [228]: arr.shape Out[228]: (3, 1) In [229]: other_arr = np.array([1,2,3]) In [230]: arr + other_arr Out[230]: array([[2, 3, 4], [3, 4, 5], [4, 5, 6]]) In [231]: other_arr.shape Out[231]: (3,)
arr的shape是(3,1)后缘维度长度为1,other_arr的shape是(3, ),other_arr低维度的值被广播到arr高维度的任意维度。
在看一个例子:
In [232]: arr = np.random.randn(4,3) In [233]: m = arr.mean(0) In [234]: m Out[234]: array([ 0.10478714, 0.93317107, -0.01853336]) In [235]: arr - m Out[235]: array([[ 0.53074894, -1.43334657, 1.11937261], [-0.09741141, 1.83929851, 0.91581349], [-0.51180403, 0.51003558, 0.1602767 ], [ 0.07846651, -0.91598753, -2.19546281]]) In [236]: (arr - m).mean(0) Out[236]: array([2.08166817e-17, 1.38777878e-16, 0.00000000e+00])上面这个例子的arr.shape是(4,3)后缘维度是3,而m的长度为3,所以可以在0轴上进行广播。
看图理解一下:
上面的那个例子如果在行上计算平均值就不一样:
In [240]: m = arr.mean(1)
In [241]: m
Out[241]: array([ 0.41206661, 1.22570848, 0.39264437, -0.6711
8633])
In [242]: arr - m
---------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-242-33627b173828> in <module>()
----> 1 arr - m
ValueError: operands could not be broadcast together with shape
s (4,3) (4,)
In [243]: arr - m.reshape(4,1)
Out[243]:
array([[ 0.22346946, -0.91224211, 0.68877264],
[-1.21833276, 1.54676111, -0.32842835],
[-0.79966126, 1.05056229, -0.25090103],
[ 0.85443997, 0.68836987, -1.54280984]])
上面这个例子的arr.shape是(4,3)后缘维度是3,而m的长度为4,不符合广播原则,所以出错。要想正确在行上做减法,就必须改变其shape为(4,1)
看一下多维的情况:
第一个数组的后缘维度是(4,2) ,第二个数组的shape是(4,2),符合广播原则
对于多维的情况,任何一维上的广播就是将数据重塑为兼容的形状。
下图是三维数组各维度上广播形状的需求:
为了简化重塑形状的过程,numpy提供了一个通过索引机制插入轴来重塑形状 的特殊语法。
In [246]: arr = np.zeros((4,4))
In [247]: re_arr = arr[:,np.newaxis,:]
In [248]: re_arr.shape
Out[248]: (4, 1, 4)
In [250]: arr = np.array([1,2,3]) In [251]: arr.shape Out[251]: (3,) In [252]: arr_1 = arr[:,np.newaxis] In [253]: arr_1.shape Out[253]: (3, 1) In [254]: arr_1 = arr[np.newaxis,:] In [256]: arr_1.shape Out[256]: (1, 3)
看一个栗子,对一个三维数组的轴2距平化:
In [257]: arr = np.random.randn(3,4,5)
In [258]: m2 = arr.mean(2)
In [259]: m2
Out[259]:
array([[ 0.13649416, 0.10628038, -0.07967465, 0.77251529],
[-0.02079456, -0.26046433, -0.03397547, -0.00820266],
[-0.17323542, 0.23429955, -0.76819986, -0.18061328]])
In [260]: re = arr - m2[:,:,np.newaxis]
In [262]: re.mean(2) # 结果大概就都是0
Out[262]:
array([[ 2.22044605e-17, -2.22044605e-17, 2.22044605e-17,
2.22044605e-17],
[ 4.44089210e-17, 0.00000000e+00, 0.00000000e+00,
1.11022302e-17],
[ 0.00000000e+00, 3.88578059e-17, -8.88178420e-17,
4.44089210e-17]])