数组广播机制

In [1]:

  1. import numpy as np

正常的加法:

In [2]:

  1. a = np.array([[ 0, 0, 0],
  2. [10,10,10],
  3. [20,20,20],
  4. [30,30,30]])
  5. b = np.array([[ 0, 1, 2],
  6. [ 0, 1, 2],
  7. [ 0, 1, 2],
  8. [ 0, 1, 2]])
  9. a + b

Out[2]:

  1. array([[ 0, 1, 2],
  2. [10, 11, 12],
  3. [20, 21, 22],
  4. [30, 31, 32]])

b 的值变成一维的 [0,1,2] 之后的加法:

In [3]:

  1. b = np.array([0,1,2])
  2.  
  3. a + b

Out[3]:

  1. array([[ 0, 1, 2],
  2. [10, 11, 12],
  3. [20, 21, 22],
  4. [30, 31, 32]])

结果一样,虽然两个数组的维数不一样,但是 Numpy 检测到 b 的维度与 a 的维度匹配,所以将 b 扩展为之前的形式,得到相同的形状。

对于更高维度,这样的扩展依然有效。

如果我们再将 a 变成一个列向量呢?

In [4]:

  1. a = np.array([0,10,20,30])
  2. a.shape = 4,1
  3. a

Out[4]:

  1. array([[ 0],
  2. [10],
  3. [20],
  4. [30]])

In [5]:

  1. b

Out[5]:

  1. array([0, 1, 2])

In [6]:

  1. a + b

Out[6]:

  1. array([[ 0, 1, 2],
  2. [10, 11, 12],
  3. [20, 21, 22],
  4. [30, 31, 32]])

可以看到,虽然两者的维度并不相同,但是Numpy还是根据两者的维度,自动将它们进行扩展然后进行计算。

对于 Numpy 来说,维度匹配当且仅当:

  • 维度相同
  • 有一个的维度是1 匹配会从最后一维开始进行,直到某一个的维度全部匹配为止,因此对于以下情况,Numpy 都会进行相应的匹配:
A B Result
3d array: 256 x 256 x 3 1d array: 3 3d array: 256 x 256 x 3
4d array: 8 x 1 x 6 x 1 3d array: 7 x 1 x 5 3d array: 8 x 7 x 6 x 5
3d array: 5 x 4 x 3 1d array: 1 3d array: 5 x 4 x 3
3d array: 15 x 4 x 13 1d array: 15 x 1 x 13 3d array: 15 x 4 x 13
2d array: 4 x 1 1d array: 3 2d array: 4 x 3

匹配成功后,Numpy 会进行运算得到相应的结果。

当然,如果相应的维度不匹配,那么Numpy会报错:

In [7]:

  1. a = np.array([0,10,20,30])
  2. a.shape

Out[7]:

  1. (4L,)

In [8]:

  1. b.shape

Out[8]:

  1. (3L,)

In [9]:

  1. a + b
  1. ---------------------------------------------------------------------------
  2. ValueError Traceback (most recent call last)
  3. <ipython-input-9-f96fb8f649b6> in <module>()
  4. ----> 1 a + b
  5.  
  6. ValueError: operands could not be broadcast together with shapes (4,) (3,)

a 转换为列向量,还是可以计算出结果:

In [10]:

  1. a[:, np.newaxis] + b

Out[10]:

  1. array([[ 0, 1, 2],
  2. [10, 11, 12],
  3. [20, 21, 22],
  4. [30, 31, 32]])

例子

In [11]:

  1. x = np.linspace(-.5,.5, 21)

In [12]:

  1. y = x[:, np.newaxis]

In [13]:

  1. x.shape

Out[13]:

  1. (21L,)

In [14]:

  1. y.shape

Out[14]:

  1. (21L, 1L)

先形成一个 21 乘 21 的网格,再计算网格到原点的距离:

In [15]:

  1. radius = np.sqrt(x ** 2 + y ** 2)

In [16]:

  1. import matplotlib.pyplot as plt
  2. %matplotlib inline
  3.  
  4. plt.imshow(radius)

Out[16]:

  1. <matplotlib.image.AxesImage at 0xa2cb358>

03.18 数组广播机制 - 图1

原文: https://nbviewer.jupyter.org/github/lijin-THU/notes-python/blob/master/03-numpy/03.18-array-broadcasting.ipynb