1.3.2.3 广播

  • numpy数组的基本操作(相加等)是元素级别的
  • 在相同大小的数组上仍然适用。 尽管如此, 也可能在不同大小的数组上进行这个操作,假如Numpy可以将这些数组转化为相同的大小:这种转化称为广播。

下图给出了一个广播的例子:

numpy_broadcasting

让我们验证一下:

In [127]:

  1. a = np.tile(np.arange(0, 40, 10), (3, 1)).T
  2. a

Out[127]:

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

In [128]:

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

Out[128]:

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

在不知道广播的时候已经使用过它!:

In [129]:

  1. a = np.ones((4, 5))
  2. a[0] = 2 # 我们将一个数组的纬度0分配给另一个数组的纬度1
  3. a

Out[129]:

  1. array([[ 2., 2., 2., 2., 2.],
  2. [ 1., 1., 1., 1., 1.],
  3. [ 1., 1., 1., 1., 1.],
  4. [ 1., 1., 1., 1., 1.]])

In [130]:

  1. a = np.ones((4, 5))
  2. print a[0]
  3. a[0] = 2 # 我们将一个数组的纬度0分配给另一个数组的纬度
  4. a
  1. [ 1\. 1\. 1\. 1\. 1.]

Out[130]:

  1. array([[ 2., 2., 2., 2., 2.],
  2. [ 1., 1., 1., 1., 1.],
  3. [ 1., 1., 1., 1., 1.],
  4. [ 1., 1., 1., 1., 1.]])

一个有用的技巧:

In [133]:

  1. a = np.arange(0, 40, 10)
  2. a.shape

Out[133]:

  1. (4,)

In [134]:

  1. a = a[:, np.newaxis] # 添加一个新的轴 -> 2D 数组
  2. a.shape

Out[134]:

  1. (4, 1)

In [135]:

  1. a

Out[135]:

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

In [136]:

  1. a + b

Out[136]:

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

广播看起来很神奇,但是,当我们要解决的问题是输出数据比输入数据有更多纬度的数组时,使用它是非常自然的。

实例:广播

让我们创建一个66号公路上城市之间距离(用公里计算)的数组:芝加哥、斯普林菲尔德、圣路易斯、塔尔萨、俄克拉何马市、阿马里洛、圣塔菲、阿尔布开克、Flagstaff、洛杉矶。

In [138]:

  1. mileposts = np.array([0, 198, 303, 736, 871, 1175, 1475, 1544, 1913, 2448])
  2. distance_array = np.abs(mileposts - mileposts[:, np.newaxis])
  3. distance_array

Out[138]:

  1. array([[ 0, 198, 303, 736, 871, 1175, 1475, 1544, 1913, 2448],
  2. [ 198, 0, 105, 538, 673, 977, 1277, 1346, 1715, 2250],
  3. [ 303, 105, 0, 433, 568, 872, 1172, 1241, 1610, 2145],
  4. [ 736, 538, 433, 0, 135, 439, 739, 808, 1177, 1712],
  5. [ 871, 673, 568, 135, 0, 304, 604, 673, 1042, 1577],
  6. [1175, 977, 872, 439, 304, 0, 300, 369, 738, 1273],
  7. [1475, 1277, 1172, 739, 604, 300, 0, 69, 438, 973],
  8. [1544, 1346, 1241, 808, 673, 369, 69, 0, 369, 904],
  9. [1913, 1715, 1610, 1177, 1042, 738, 438, 369, 0, 535],
  10. [2448, 2250, 2145, 1712, 1577, 1273, 973, 904, 535, 0]])

route66

许多基于网格或者基于网络的问题都需要使用广播。例如,如果要计算10X10网格中每个点到原点的数据,可以这样:

In [139]:

  1. x, y = np.arange(5), np.arange(5)[:, np.newaxis]
  2. distance = np.sqrt(x ** 2 + y ** 2)
  3. distance

Out[139]:

  1. array([[ 0\. , 1\. , 2\. , 3\. , 4\. ],
  2. [ 1\. , 1.41421356, 2.23606798, 3.16227766, 4.12310563],
  3. [ 2\. , 2.23606798, 2.82842712, 3.60555128, 4.47213595],
  4. [ 3\. , 3.16227766, 3.60555128, 4.24264069, 5\. ],
  5. [ 4\. , 4.12310563, 4.47213595, 5\. , 5.65685425]])

或者用颜色:

In [141]:

  1. plt.pcolor(distance)
  2. plt.colorbar()

Out[141]:

  1. <matplotlib.colorbar.Colorbar instance at 0x10d8d7170>

1.3.2.3 广播 - 图3

评论 : numpy.ogrid 函数允许直接创建上一个例子中两个重要纬度向量X和Y:

In [142]:

  1. x, y = np.ogrid[0:5, 0:5]
  2. x, y

Out[142]:

  1. (array([[0],
  2. [1],
  3. [2],
  4. [3],
  5. [4]]), array([[0, 1, 2, 3, 4]]))

In [143]:

  1. x.shape, y.shape

Out[143]:

  1. ((5, 1), (1, 5))

In [144]:

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

因此, np.ogrid 就非常有用,只要我们是要处理网格计算。另一方面, 在一些无法(或者不想)从广播中收益的情况下,np.mgrid 直接提供了由索引构成的矩阵:

In [145]:

  1. x, y = np.mgrid[0:4, 0:4]
  2. x

Out[145]:

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

In [146]:

  1. y

Out[146]:

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