5-Numpy數組廣播

廣播

廣播允許在不同大小的數組上執行加減乘除的二進制運算 例如

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. 首先根據規則1,我們看到數組a的維數較少,因此我們在數組的左側填充了1維使其成為和M相同維度的二維數組:

    M.shape -> (2, 3)
    a.shape -> (1, 3)

  2. 根據規則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)
  1. 首先我們創造一個,3*1的二維數組和一個一維數組

    a.shape = (3, 1)
    b.shape = (3,)

  2. 規則1說我們必須填充b的形狀使其形成二維數組(1行3列):

    a.shape -> (3, 1)
    b.shape -> (1, 3)

  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)]

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容