廣播
廣播允許在不同大小的數組上執行加減乘除的二進制運算 例如
In [1]: import numpy as np
In [2]: a = np.array([0, 1, 2])
...: b = np.array([5, 5, 5])
In [3]: a*b
Out[3]: array([ 0, 5, 10])
NumPy廣播的優點是在復制值得過程中沒有占用額外得空間,但是在我們考慮廣播時,它是一種有用的思維模型。
例如如下對三維數組數值擴展
In [8]: m=np.ones((3,3))
In [9]: 3+m
Out[9]:
array([[4., 4., 4.],
[4., 4., 4.],
[4., 4., 4.]])
兩個數組相加擴展
In [17]: a = np.arange(3)
...: b = np.arange(3)[:, np.newaxis]
...: print(a)
...: print(b)
[0 1 2]
[[0]
[1]
[2]]
# 兩個數組相加(注意數組非矩陣)
In [18]:a + b
Out[18]:
array([[0, 1, 2],
[1, 2, 3],
[2, 3, 4]])
就像我們拉伸或廣播一個值以匹配另一個值的形狀一樣,這里拉伸了a和b以匹配一個通用形狀,結果是一個二維數組!
下圖顯示了這些示例的幾何形狀(可以在附錄中找到生成該圖的代碼,并改編自astroML文檔中發布的源)。
[圖片上傳失敗...(image-d405c3-1584512066939)]
這些圖中額外的內存實際上并沒有在操作過程中分配.這里時為了從概念理解。
廣播得規則
NumPy中的廣播遵循一套嚴格的規則來確定兩個數組之間的交互:
規則1:如果兩個數組的維數不同,則維數較少的數組的形狀將在其前(左側)填充。
規則2:如果兩個數組的形狀在任何維度上都不匹配,則將在該維度上形狀等于1的數組拉伸以匹配其他形狀。
規則3:如果尺寸在任何維度上都不相同,且都不等于1,則會引發錯誤。
廣播示例1
下面詳細來說明
In [23]: M = np.ones((2, 3))
...: a = np.arange(3)
- 首先創建得兩個數組,M 為2行3列的二維數組,a為一個1行的一維數組
-
首先根據規則1,我們看到數組a的維數較少,因此我們在數組的左側填充了1維使其成為和M相同維度的二維數組:
M.shape -> (2, 3)
a.shape -> (1, 3) -
根據規則2,我們現在看到維度相同,但是尺寸不一致,因此我們拉伸該維度以使其匹配:
M.shape -> (2, 3)
a.shape -> (2, 3)
最終我們通過拉伸變換使其形狀匹配,我們看到最終形狀將是(2,3):
In [23]: M = np.ones((2, 3))
...: a = np.arange(3)
In [24]: M+a
Out[24]:
array([[1., 2., 3.],
[1., 2., 3.]])
廣播示例2
讓我們看下兩個數組都需要拉伸變換來適應匹配的
In [28]: a = np.arange(3).reshape((3, 1))
...: b = np.arange(3)
-
首先我們創造一個,3*1的二維數組和一個一維數組
a.shape = (3, 1)
b.shape = (3,) -
規則1說我們必須填充b的形狀使其形成二維數組(1行3列):
a.shape -> (3, 1)
b.shape -> (1, 3) 根據規則2,我們將每個升級,以匹配另一個數組的相應大小(都擴展成3*3的數組):
In [30]: a+b
Out[30]:
array([[0, 1, 2],
[1, 2, 3],
[2, 3, 4]])
廣播示例3
我們在看兩個不匹配的數組
In [31]: M = np.ones((3, 2))
...: a = np.arange(3)
考慮上面a和M,分析簡略如下
首先a M
M.shape = (3, 2)
a.shape = (3,)
根據規則一,對a擴展成
M.shape -> (3, 2)
a.shape -> (1, 3)
根據規則2,對a 的行擴展
M.shape -> (3, 2)
a.shape -> (3, 3)
擴展后我們發現,兩者不匹配執行
In [32]: a+M
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-32-60afc280ce5f> in <module>
*此處可能存在的混亂:可以想象通過將a的形狀用右邊而不是左邊的形狀填充來使a和M兼容。但這不是廣播規則的工作方式!這種靈活性在某些情況下可能有用,但可能會導致歧義。如果想要右側填充,則可以通過重塑數組來明確地做到這一點(我們將使用《 NumPy數組基礎》中引入的np.newaxis關鍵字):
# 將a變換 成3*1的數組和M廣播
In [34]: a[:, np.newaxis].shape
Out[34]: (3, 1)
In [35]: M + a[:, np.newaxis]
Out[35]:
array([[1., 1.],
[2., 2.],
[3., 3.]])
*同樣除了+ 還可以用于其他函數例如log等
廣播操作練習
在上一節中,我們看到ufunc允許NumPy用戶消除顯式編寫慢速Python循環的需要。廣播擴展了此功能。一個常見的示例是將數據陣列居中時。假設您有一個包含10個觀測值的數組,每個觀測值包含3個值。,我們將其存儲在10×3數組中:
In [43]: a=np.arange(9).reshape((3,3))
In [44]: a
Out[44]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
#我們可以使用第一維上的均值合計來計算每個特征的均值:
In [46]: a.mean(0)
Out[46]: array([3., 4., 5.])
繪制二維函數
廣播非常有用的一個地方是基于二維函數顯示圖像。如果我們要定義一個函數z= f(x,y),可以使用廣播來計算整個網格中的函數
這里我們用py代碼執行
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np
#我們將使用Matplotlib繪制此二維數組(這些工具將在“密度和輪廓圖”中進行全面討論):
import matplotlib.pyplot as plt
x=np.linspace(0,5,50)
y=np.linspace(0,5,50)[:,np.newaxis]
z=np.sin(x)**2 + np.cos(6+y*x)*np.cos(x)
plt.imshow(z, origin='lower', extent=[0, 5, 0, 5],cmap='viridis')
plt.colorbar();
plt.show() #關鍵的地方
[圖片上傳失敗...(image-8ea90c-1584512066939)]