python科學(xué)計(jì)算之numpy——ufunc函數(shù)用法
寫(xiě)在前面
ufunc是universal function的縮寫(xiě),意思是這些函數(shù)能夠作用于narray對(duì)象的每一個(gè)元素上,而不是針對(duì)narray對(duì)象操作,numpy提供了大量的ufunc的函數(shù)。這些函數(shù)在對(duì)narray進(jìn)行運(yùn)算的速度比使用循環(huán)或者列表推導(dǎo)式要快很多,但請(qǐng)注意,在對(duì)單個(gè)數(shù)值進(jìn)行運(yùn)算時(shí),python提供的運(yùn)算要比numpy效率高。
四則運(yùn)算
numpy提供的四則ufunc有如下一些:
numpy提供的四則運(yùn)算unfunc能夠大大的提高計(jì)算效率,但如果運(yùn)算式復(fù)雜,且參與運(yùn)算的narray過(guò)大,會(huì)產(chǎn)生大量的中間結(jié)果,從而降低計(jì)算效率。例如:計(jì)算x=a*b+c時(shí),實(shí)際上會(huì)按照如下方式計(jì)算:
t = a*b x = t+c del t
這會(huì)產(chǎn)生兩次內(nèi)存分配,一次時(shí)x,一次時(shí)t,所以按照
x = a*b x = x+c
會(huì)節(jié)省一次內(nèi)存的分配,從而提高效率。
比較運(yùn)算 & bool運(yùn)算
numpy同時(shí)提供了=、<、>等這些比較運(yùn)算符,這些運(yùn)算符的結(jié)果是bool值或者bool數(shù)組。
np.array([1,2,3]) < np.array([0,3,4]) array([False, True, True], dtype=bool)
邏輯運(yùn)算and、or、not、xor等由于python提供了,所以numpy的這些邏輯運(yùn)算符是以logical_開(kāi)頭的函數(shù)
a = np.arange(5) b= np.arange(4,-1,-1) ## print a==b [False False True False False] ## print a>b [False False False True True] ## print np.logical_or(a == b, a > b) [False False True True True]
對(duì)兩個(gè)bool數(shù)組進(jìn)行邏輯運(yùn)算時(shí),將發(fā)生ValueError異常,因?yàn)閎ool值也是True和False,numpy無(wú)法確定運(yùn)算目的,可以使用numpy.any()和numpy.all()函數(shù),他們的使用方法和python的any()、all()函數(shù)用法相同。以bitwise_開(kāi)頭的函數(shù)時(shí)用于位運(yùn)算,如(bitwise_and、bitwise_or)等,也可以使用&、|、~和^來(lái)進(jìn)行運(yùn)算。
除了numpy提供的內(nèi)置ufunc函數(shù),用戶也可以編寫(xiě)自定義的ufunc函數(shù),方式是:
1. 編寫(xiě)對(duì)單個(gè)數(shù)值計(jì)算的目的函數(shù);
2. 利用np.frompyfunc(func, nin, nout)將其轉(zhuǎn)換為ufunc函數(shù),其中func是上面編寫(xiě)的目的函數(shù),nin是輸入的參數(shù)個(gè)數(shù),nout是返回值的個(gè)數(shù)。
## 基本形式 u_func = np.frompyfunc(func,nin,nout) ret = u_func(narray_obj,param1,param2..)
這里返回的ret是object類型,所以實(shí)際上需要用astype()轉(zhuǎn)換為目的類型。numpy.vectorize()也實(shí)現(xiàn)了和numpy.frompyfunc()一樣的功能,區(qū)別是前者可以t通過(guò)otypes指定返回值的類型,不用再用astype()進(jìn)行轉(zhuǎn)換。
## 基本形式 u_func = np.frompyfunc(func,otypes=[dtype1,dtype2..] ret = u_func(narray_object,param1,param2..)
廣播
先看個(gè)例子:
a = np.arange(0,60,10).reshape(-1,1) b = np.arange(0,5) #a array([[ 0], [10], [20], [30], [40], [50]]) #b array([0, 1, 2, 3, 4])
ok,現(xiàn)在計(jì)算a+b,不過(guò)現(xiàn)在有一個(gè)問(wèn)題,a和b的維度不一樣,那應(yīng)該怎么加?先看看結(jié)果吧
# a+b array([[ 0, 1, 2, 3, 4], [10, 11, 12, 13, 14], [20, 21, 22, 23, 24], [30, 31, 32, 33, 34], [40, 41, 42, 43, 44], [50, 51, 52, 53, 54]])
結(jié)果來(lái)看,是用a的每一行的元素(這里a為列向量,每一行只有一個(gè)元素)與b的每一個(gè)元素相加,相當(dāng)于:
a=array([[ 0, 0, 0, 0, 0], [10, 10, 10, 10, 10], [20, 20, 20, 20, 20], [30, 30, 30, 30, 30], [40, 40, 40, 40, 40], [50, 50, 50, 50, 50]])
而b是一個(gè)行向量,現(xiàn)在我們將這一個(gè)行向量重復(fù)6次,和a的第0軸長(zhǎng)度相同,構(gòu)成一個(gè)二維數(shù)組,相當(dāng)于:
b=array([[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]])
現(xiàn)在,再進(jìn)行相加,自然就是對(duì)用元素相加了,也就是上面的結(jié)果,這就是numpy中的廣播,對(duì)進(jìn)行運(yùn)算的兩個(gè)narray對(duì)象shape不一樣時(shí),進(jìn)行的維度補(bǔ)齊??偟膩?lái)說(shuō),numpy的廣播規(guī)則基于下面4個(gè)規(guī)則:
讓所有輸入數(shù)姐都向其中維數(shù)最多的數(shù)組看齊,shape屬性中不足的部分都通過(guò)在前面加1補(bǔ)齊; 如上面的輸入中,a.shape=(6,1),b.shape=(,5),a的維數(shù)是2,b的維數(shù)是1,所以b向a看齊,并且用1補(bǔ)齊,那么b.shape=(1,5)。
輸出數(shù)組的shape屬性是輸入數(shù)組的shape屬性的各個(gè)軸上的最大值 輸出是各軸上最大值,所以a+b的輸出的shape應(yīng)該是(6,5);
如果輸入數(shù)組的某個(gè)軸的長(zhǎng)度 為 1或與輸出數(shù)組的對(duì)應(yīng)軸的長(zhǎng)度相同,這個(gè)數(shù)組能夠用來(lái)計(jì)算,否則出錯(cuò)
當(dāng)輸入數(shù)組的某個(gè)軸的長(zhǎng)度為1吋,沿著此軸運(yùn)算時(shí)都用此軸上的第一組值
由于廣播在numpy計(jì)算中比較常見(jiàn),所以numpy提供了ogrid和mgrid來(lái)創(chuàng)建廣播計(jì)算的數(shù)組,前者返回的是兩個(gè)向量,后者返回的是進(jìn)行廣播運(yùn)算的數(shù)組。
x,y = np.ogrid[:5,:5] # x array([[0], [1], [2], [3], [4]]) # y array([[0, 1, 2, 3, 4]]) x,y=np.mgrid[:5,:5] # x [[0, 0, 0, 0, 0], [1, 1, 1, 1, 1], [2, 2, 2, 2, 2], [3, 3, 3, 3, 3], [4, 4, 4, 4, 4]] #y [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]]
ogrid[]參數(shù)是有兩種形式(1):[start:end:step]即起點(diǎn)、終點(diǎn)和步長(zhǎng);(2):[start:end:len]即起點(diǎn)、終點(diǎn)和數(shù)組長(zhǎng)度,這里的長(zhǎng)度為了和步長(zhǎng)區(qū)分,在傳入時(shí)時(shí)以虛數(shù)方式傳入的,例如[1,5,4j]將產(chǎn)生[1,2,3,4]這樣的數(shù)組。
另外廣播支持特殊的下標(biāo)None,意義時(shí)在對(duì)應(yīng)位置上產(chǎn)生1的新軸,例如a[None,:]等效于a.reshape((1,-1)),a[:,None]等效于a.reshape((-1,1)),另外,np.ix_()能將一維數(shù)組轉(zhuǎn)換為能進(jìn)行廣播的二維數(shù)組:
x=np.array([0,1,4,10]) y=np.array([2,3,8]) gy,gx=np.ix_(y,x) #print gy [[2] [3] [8]] #print gx [[ 0 1 4 10]] # gx+gy array([[ 2, 3, 6, 12], [ 3, 4, 7, 13], [ 8, 9, 12, 18]])
np.ix_()支持多個(gè)參數(shù),從而支持n維空間的廣播計(jì)算。
ufunc方法
ufunc函數(shù)對(duì)象本身還有一些方法函數(shù),這些方法只對(duì)兩個(gè)輸入、一個(gè)輸出的ufunc 函數(shù)有效,其他的ufunc對(duì)象調(diào)用這些方法時(shí)會(huì)拋出ValueError異常。
(1). reduce(),沿著指定軸對(duì)數(shù)組進(jìn)行操作,相當(dāng)于將相應(yīng)的操作放到該軸元素之間。
np.add.reduce([1,2,3]) #1+2+3=6 np.add.reduce([[1,2,3],[4,5,6]]) #[1+4,2+5,3+6]=[5,7,9] np.add.reduce([[1,2,3],[4,5,6]],axis=1) #[1+2+3,4+5+6]=[6,15]
(2). accumulate()和reduce()類似,區(qū)別時(shí)是前者會(huì)保留中間結(jié)果:
np.add.accumulate([1,2,3]) #[1,1+2,1+2+3]=[1,3,6] np.add.accumulate([[1,2,3],[4,5,6]],axis=1) # array([[ 1, 3, 6], [ 4, 9, 15]])
(3). reduceat()方法計(jì)算多紐reduce()的結(jié)果,通 過(guò) indices參數(shù)指定一系列的起始和終止位置。它的計(jì)算有些特別,,計(jì)算的方法如下:
if indices[i] < indices[i+1]: result[i] = <op>.reduce(a[indices[i]:indices[i+1]]) else: result[i] = a[indices[i]] #result[-1]的計(jì)算如下: <op>.reduce(a[indices[-1]:])
例:
a = np.array([1,2,3,4]) result = np.add.reduceat(a, indices=[0,1,0,2,0,3,0]) ## result array([1,2,3,3,6,4,10]) ## 計(jì)算過(guò)程如下: : a[0] -> 1 : a[1] -> 2 : a[0] + a[1] -> 1 + 2 : a[2] -> 3 : a[0] + a[1] + a[2] -> 1 + 2 + 3 = 6 : a[3] -> 4 :a[0] + a[1] + a[2] + a[4] - > 1 + 2 + 3 + 4 = 1 0
再看多維數(shù)組
在前一篇文章中我們提到過(guò)多維數(shù)組,現(xiàn)在我們回頭再看看多維數(shù)組的下標(biāo)取數(shù)據(jù)。首先,多維數(shù)組的下標(biāo)應(yīng)該是一個(gè)長(zhǎng)度和數(shù)組的維數(shù)相同的元組。如栗下標(biāo)元組的長(zhǎng)度比數(shù)組的維數(shù)大,就會(huì)出錯(cuò);如果小,就 會(huì) 在 下 標(biāo) 元 組 的 后 而 補(bǔ) ,使得它的長(zhǎng)度與數(shù)組維數(shù)相同。如果下標(biāo)對(duì)象不是元組,則 numpy會(huì)首先把它轉(zhuǎn)換為元組。這種轉(zhuǎn)換可能會(huì)和用戶所希望的不一致,因此為了避免出現(xiàn)問(wèn)題,請(qǐng) “顯式”地使用元組作為下標(biāo)。
a = np.arange(3*4*5).reshape(3,4,5) array([[[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]], [[20, 21, 22, 23, 24], [25, 26, 27, 28, 29], [30, 31, 32, 33, 34], [35, 36, 37, 38, 39]], [[40, 41, 42, 43, 44], [45, 46, 47, 48, 49], [50, 51, 52, 53, 54], [55, 56, 57, 58, 59]]]) lidx=[[0],[1]] #a[lidx] aidx = np.array(lidx) #a[aidx] array([[[[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]], [[[20, 21, 22, 23, 24], [25, 26, 27, 28, 29], [30, 31, 32, 33, 34], [35, 36, 37, 38, 39]]]])
可以看到,numpy把列表[[0],[1]]轉(zhuǎn)換成元組([0],[1]),而把數(shù)組對(duì)象轉(zhuǎn)換成(aidx,:,:)。
整數(shù)數(shù)組和切片做為下標(biāo)
如果利用數(shù)組作為下標(biāo),但數(shù)組的維度都不一樣,那么這個(gè)時(shí)候這些數(shù)組將會(huì)應(yīng)用廣播規(guī)則把這些數(shù)組轉(zhuǎn)換成一樣,轉(zhuǎn)換的規(guī)則是上面說(shuō)到的先用1補(bǔ)足然后取各個(gè)維度的最大值。
i0 = np.array([[1,2,1],[0,1,0]]) i1 = np.array([[[0]],[[1]]]) i2 = np.array([[[2,3,2]]]) #print i0.shape (2, 3) #print i1.shape (2, 1, 1) #print i2.shape (1, 1, 3) # i0補(bǔ)齊之后為 (1,2,3),然后取最大值為 (2,2,3)
這里將所有的數(shù)組進(jìn)行廣播,把所有的數(shù)組轉(zhuǎn)換成shape=(2,2,3),利用numpy.broadcast_arrays()可以查看廣播后的數(shù)組:
id0,id1,id2=np.broadcast_arrays(i0,i1,i2) #id0 [[[1 2 1] [0 1 0]] [[1 2 1] [0 1 0]] #id1 [[[0 0 0] [0 0 0]] [[1 1 1] [1 1 1]]] #id2 [[[2 3 2] [2 3 2]] [[2 3 2] [2 3 2]]]
然后利用下標(biāo)取元素時(shí),例如i,j,k=1,1,1時(shí),取得的元素應(yīng)該是a[id0[i,j,k],id1[i,j,k],id2[i,j,k]]=a[1,1,3]=28。下標(biāo)中含有切片時(shí),首先來(lái)看第一種,就是整數(shù)數(shù)組時(shí)連續(xù)的,也就是數(shù)組之間沒(méi)有切片,例如a[1:3,i0,i1],這種情況下,首先會(huì)把整數(shù)數(shù)組(i0,i1)廣播,然后將切片的長(zhǎng)度放到相應(yīng)的位置構(gòu)成一個(gè)維度,i0,i1廣播后的shape=(2,2,3),切片的長(zhǎng)度為2,所以最后的shape=(2,2,2,3)。最后的結(jié)果是a[1:3,id0[i,j,k],id1[i,j,k]]。再者,如果切片是再整數(shù)數(shù)組之間,那么同樣會(huì)將數(shù)組廣播,然后把切片位置替換為數(shù)組的維度或者切片的長(zhǎng)度添加到索引的最后面,如a[i0,:,i1],i0,i1廣播后的shape=(2,2,3),數(shù)組a的第二個(gè)軸的長(zhǎng)度為4,所以最后的shape=(2,2,3,4)。
bool數(shù)組做為下標(biāo)
用bool數(shù)組作為下標(biāo)時(shí),會(huì)將bool數(shù)組中為T(mén)rue的索引組成一個(gè)整數(shù)數(shù)組,然后以此數(shù)組作為下標(biāo)。相當(dāng)于用numpy.nonzero(bool_array)的結(jié)果,例如:
b2 = np.array([[True,False,True],[True,False,False]]) np.nonzero(b2) ## (array([0, 0, 1]), array([0, 2, 0])) ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## 相當(dāng)于取[0,0],[0,2],[1,0]
除此之外,如果bool數(shù)組中有切片,那么相當(dāng)于將bool值轉(zhuǎn)換成nonzero()后的整數(shù)數(shù)組,切片位置不變。
以上這篇python科學(xué)計(jì)算之numpy——ufunc函數(shù)用法就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
TensorFlow人工智能學(xué)習(xí)按索引取數(shù)據(jù)及維度變換詳解
這篇文章主要為大家介紹了TensorFlow人工智能學(xué)習(xí)按索引取數(shù)據(jù)及維度變換的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-11-11OpenCV實(shí)戰(zhàn)案例之車(chē)道線識(shí)別詳解
計(jì)算機(jī)視覺(jué)在自動(dòng)化系統(tǒng)觀測(cè)環(huán)境、預(yù)測(cè)該系統(tǒng)控制器輸入值等方面起著至關(guān)重要的作用,下面這篇文章主要給大家介紹了關(guān)于OpenCV實(shí)戰(zhàn)案例之車(chē)道線識(shí)別的相關(guān)資料,需要的朋友可以參考下2022-10-10pytorch中的matmul與mm,bmm區(qū)別說(shuō)明
這篇文章主要介紹了pytorch中的matmul與mm,bmm區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-0511個(gè)Python Pandas小技巧讓你的工作更高效(附代碼實(shí)例)
這篇文章主要介紹了11個(gè)Python Pandas小技巧讓你的工作更高效(附代碼實(shí)例),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-04-04python區(qū)塊鏈簡(jiǎn)易版交易完善挖礦獎(jiǎng)勵(lì)示例
這篇文章主要介紹了python區(qū)塊鏈簡(jiǎn)易版交易完善挖礦獎(jiǎng)勵(lì)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05Python面向?qū)ο蟪绦蛟O(shè)計(jì)示例小結(jié)
這篇文章主要介紹了Python面向?qū)ο蟪绦蛟O(shè)計(jì),結(jié)合實(shí)例形式總結(jié)分析了Python面向?qū)ο蟪绦蛟O(shè)計(jì)中比較常見(jiàn)的類定義、實(shí)例化、繼承、私有變量等相關(guān)使用技巧與操作注意事項(xiàng),需要的朋友可以參考下2019-01-01python實(shí)時(shí)監(jiān)控cpu小工具
這篇文章主要為大家詳細(xì)介紹了python實(shí)時(shí)監(jiān)控cpu的小工具,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06