廣播
廣播允許在不同大小的數(shù)組上執(zhí)行加減乘除的二進(jìn)制運(yùn)算 例如
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廣播的優(yōu)點(diǎn)是在復(fù)制值得過(guò)程中沒(méi)有占用額外得空間,但是在我們考慮廣播時(shí)南缓,它是一種有用的思維模型目锭。
例如如下對(duì)三維數(shù)組數(shù)值擴(kuò)展
In [8]: m=np.ones((3,3))
In [9]: 3+m
Out[9]:
array([[4., 4., 4.],
[4., 4., 4.],
[4., 4., 4.]])
兩個(gè)數(shù)組相加擴(kuò)展
In [17]: a = np.arange(3)
...: b = np.arange(3)[:, np.newaxis]
...: print(a)
...: print(b)
[0 1 2]
[[0]
[1]
[2]]
# 兩個(gè)數(shù)組相加(注意數(shù)組非矩陣)
In [18]:a + b
Out[18]:
array([[0, 1, 2],
[1, 2, 3],
[2, 3, 4]])
就像我們拉伸或廣播一個(gè)值以匹配另一個(gè)值的形狀一樣,這里拉伸了a和b以匹配一個(gè)通用形狀村缸,結(jié)果是一個(gè)二維數(shù)組祠肥!
下圖顯示了這些示例的幾何形狀(可以在附錄中找到生成該圖的代碼,并改編自astroML文檔中發(fā)布的源)梯皿。
[圖片上傳失敗...(image-d405c3-1584512066939)]
這些圖中額外的內(nèi)存實(shí)際上并沒(méi)有在操作過(guò)程中分配.這里時(shí)為了從概念理解仇箱。
廣播得規(guī)則
NumPy中的廣播遵循一套嚴(yán)格的規(guī)則來(lái)確定兩個(gè)數(shù)組之間的交互:
規(guī)則1:如果兩個(gè)數(shù)組的維數(shù)不同县恕,則維數(shù)較少的數(shù)組的形狀將在其前(左側(cè))填充。
規(guī)則2:如果兩個(gè)數(shù)組的形狀在任何維度上都不匹配剂桥,則將在該維度上形狀等于1的數(shù)組拉伸以匹配其他形狀忠烛。
規(guī)則3:如果尺寸在任何維度上都不相同,且都不等于1权逗,則會(huì)引發(fā)錯(cuò)誤佳镜。
廣播示例1
下面詳細(xì)來(lái)說(shuō)明
In [23]: M = np.ones((2, 3))
...: a = np.arange(3)
- 首先創(chuàng)建得兩個(gè)數(shù)組,M 為2行3列的二維數(shù)組苛让,a為一個(gè)1行的一維數(shù)組
-
首先根據(jù)規(guī)則1液斜,我們看到數(shù)組a的維數(shù)較少,因此我們?cè)跀?shù)組的左側(cè)填充了1維使其成為和M相同維度的二維數(shù)組:
M.shape -> (2, 3)
a.shape -> (1, 3) -
根據(jù)規(guī)則2奔垦,我們現(xiàn)在看到維度相同屹耐,但是尺寸不一致,因此我們拉伸該維度以使其匹配:
M.shape -> (2, 3)
a.shape -> (2, 3)
最終我們通過(guò)拉伸變換使其形狀匹配椿猎,我們看到最終形狀將是(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
讓我們看下兩個(gè)數(shù)組都需要拉伸變換來(lái)適應(yīng)匹配的
In [28]: a = np.arange(3).reshape((3, 1))
...: b = np.arange(3)
-
首先我們創(chuàng)造一個(gè),3*1的二維數(shù)組和一個(gè)一維數(shù)組
a.shape = (3, 1)
b.shape = (3,) -
規(guī)則1說(shuō)我們必須填充b的形狀使其形成二維數(shù)組(1行3列):
a.shape -> (3, 1)
b.shape -> (1, 3) 根據(jù)規(guī)則2犯眠,我們將每個(gè)升級(jí)按灶,以匹配另一個(gè)數(shù)組的相應(yīng)大小(都擴(kuò)展成3*3的數(shù)組):
In [30]: a+b
Out[30]:
array([[0, 1, 2],
[1, 2, 3],
[2, 3, 4]])
廣播示例3
我們?cè)诳磧蓚€(gè)不匹配的數(shù)組
In [31]: M = np.ones((3, 2))
...: a = np.arange(3)
考慮上面a和M筐咧,分析簡(jiǎn)略如下
首先a M
M.shape = (3, 2)
a.shape = (3,)
根據(jù)規(guī)則一鸯旁,對(duì)a擴(kuò)展成
M.shape -> (3, 2)
a.shape -> (1, 3)
根據(jù)規(guī)則2,對(duì)a 的行擴(kuò)展
M.shape -> (3, 2)
a.shape -> (3, 3)
擴(kuò)展后我們發(fā)現(xiàn)量蕊,兩者不匹配執(zhí)行
In [32]: a+M
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-32-60afc280ce5f> in <module>
*此處可能存在的混亂:可以想象通過(guò)將a的形狀用右邊而不是左邊的形狀填充來(lái)使a和M兼容铺罢。但這不是廣播規(guī)則的工作方式!這種靈活性在某些情況下可能有用残炮,但可能會(huì)導(dǎo)致歧義韭赘。如果想要右側(cè)填充,則可以通過(guò)重塑數(shù)組來(lái)明確地做到這一點(diǎn)(我們將使用《 NumPy數(shù)組基礎(chǔ)》中引入的np.newaxis關(guān)鍵字):
# 將a變換 成3*1的數(shù)組和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.]])
*同樣除了+ 還可以用于其他函數(shù)例如log等
廣播操作練習(xí)
在上一節(jié)中势就,我們看到ufunc允許NumPy用戶消除顯式編寫(xiě)慢速Python循環(huán)的需要泉瞻。廣播擴(kuò)展了此功能。一個(gè)常見(jiàn)的示例是將數(shù)據(jù)陣列居中時(shí)苞冯。假設(shè)您有一個(gè)包含10個(gè)觀測(cè)值的數(shù)組袖牙,每個(gè)觀測(cè)值包含3個(gè)值。抱完,我們將其存儲(chǔ)在10×3數(shù)組中:
In [43]: a=np.arange(9).reshape((3,3))
In [44]: a
Out[44]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
#我們可以使用第一維上的均值合計(jì)來(lái)計(jì)算每個(gè)特征的均值:
In [46]: a.mean(0)
Out[46]: array([3., 4., 5.])
繪制二維函數(shù)
廣播非常有用的一個(gè)地方是基于二維函數(shù)顯示圖像贼陶。如果我們要定義一個(gè)函數(shù)z= f(x,y),可以使用廣播來(lái)計(jì)算整個(gè)網(wǎng)格中的函數(shù)
這里我們用py代碼執(zhí)行
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np
#我們將使用Matplotlib繪制此二維數(shù)組(這些工具將在“密度和輪廓圖”中進(jìn)行全面討論):
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() #關(guān)鍵的地方
[圖片上傳失敗...(image-8ea90c-1584512066939)]