NumPy在數(shù)據(jù)分析就像Django在web開發(fā)中那樣出名,就是老大哥,也是在工作中最常用的庫,沒有之一,今天給大家詳細(xì)的講解一下這個庫的妙用! 103456743
進(jìn)階 廣播法則(rule) 廣播法則能使通用函數(shù)有意義地處理不具有相同形狀的輸入。 廣播第一法則是,如果所有的輸入數(shù)組維度不都相同,一個“1”將被重復(fù)地添加在維度較小的數(shù)組上直至所有的數(shù)組擁有一樣的維度。 廣播第二法則確定長度為1的數(shù)組沿著特殊的方向表現(xiàn)地好像它有沿著那個方向最大形狀的大小。對數(shù)組來說,沿著那個維度的數(shù)組元素的值理應(yīng)相同。 應(yīng)用廣播法則之后,所有數(shù)組的大小必須匹配。更多細(xì)節(jié)可以從這個文檔找到。 第二種通過布爾來索引的方法更近似于整數(shù)索引;對數(shù)組的每個維度我們給一個一維布爾數(shù)組來選擇我們想要的切片。 >>> a = arange(12).reshape(3,4)
>>> b1 = array([False,True,True]) # first dim selection
>>> b2 = array([True,False,True,False]) # second dim selection
>>>
>>> a[b1,:] # selecting rows
array([[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>>
>>> a[b1] # same thing
array([[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>>
>>> a[:,b2] # selecting columns
array([[ 0, 2],
[ 4, 6],
[ 8, 10]])
>>>
>>> a[b1,b2] # a weird thing to do
array([ 4, 10]) 注意一維數(shù)組的長度必須和你想要切片的維度或軸的長度一致,在之前的例子中,b1是一個秩為1長度為三的數(shù)組(a的行數(shù)),b2(長度為4)與a的第二秩(列)相一致。7 ix_()函數(shù)
>>> a = array([2,3,4,5])
>>> b = array([8,5,4])
>>> c = array([5,4,6,8,3])
>>> ax,bx,cx = ix_(a,b,c)
>>> ax
array([[[2]],
[[3]],
[[4]],
[[5]]])
>>> bx
array([[[8],
[5],
[4]]])
>>> cx
array([[[5, 4, 6, 8, 3]]])
>>> ax.shape, bx.shape, cx.shape
((4, 1, 1), (1, 3, 1), (1, 1, 5))
>>> result = ax bx*cx
>>> result
array([[[42, 34, 50, 66, 26],
[27, 22, 32, 42, 17],
[22, 18, 26, 34, 14]],
[[43, 35, 51, 67, 27],
[28, 23, 33, 43, 18],
[23, 19, 27, 35, 15]],
[[44, 36, 52, 68, 28],
[29, 24, 34, 44, 19],
[24, 20, 28, 36, 16]],
[[45, 37, 53, 69, 29],
[30, 25, 35, 45, 20],
[25, 21, 29, 37, 17]]])
>>> result[3,2,4]
17
>>> a[3] b[2]*c[4]
17 你也可以實行如下簡化: def ufunc_reduce(ufct, *vectors):
vs = ix_(*vectors)
r = ufct.identity
for v in vs:
r = ufct(r,v)
return r 然后這樣使用它: >>> ufunc_reduce(add,a,b,c)
array([[[15, 14, 16, 18, 13],
[12, 11, 13, 15, 10],
[11, 10, 12, 14, 9]],
[[16, 15, 17, 19, 14],
[13, 12, 14, 16, 11],
[12, 11, 13, 15, 10]],
[[17, 16, 18, 20, 15],
[14, 13, 15, 17, 12],
[13, 12, 14, 16, 11]],
[[18, 17, 19, 21, 16],
[15, 14, 16, 18, 13],
[14, 13, 15, 17, 12]]]) 這個reduce與ufunc.reduce(比如說add.reduce)相比的優(yōu)勢在于它利用了廣播法則,避免了創(chuàng)建一個輸出大小乘以向量個數(shù)的參數(shù)數(shù)組。8 用字符串索引 參見RecordArray。 線性代數(shù) 繼續(xù)前進(jìn),基本線性代數(shù)包含在這里。 簡單數(shù)組運(yùn)算 參考numpy文件夾中的linalg.py獲得更多信息 >>> from numpy import *
>>> from numpy.linalg import *
>>> a = array([[1.0, 2.0], [3.0, 4.0]])
>>> print a
[[ 1. 2.]
[ 3. 4.]]
>>> a.transpose()
array([[ 1., 3.],
[ 2., 4.]])
>>> inv(a)
array([[-2. , 1. ],
[ 1.5, -0.5]])
>>> u = eye(2) # unit 2x2 matrix; 'eye' represents 'I'
>>> u
array([[ 1., 0.],
[ 0., 1.]])
>>> j = array([[0.0, -1.0], [1.0, 0.0]])
>>> dot (j, j) # matrix product
array([[-1., 0.],
[ 0., -1.]])
>>> trace(u) # trace
2.0
>>> y = array([[5.], [7.]])
>>> solve(a, y)
array([[-3.],
[ 4.]])
>>> eig(j)
(array([ 0. 1.j, 0.-1.j]),
array([[ 0.70710678 0.j, 0.70710678 0.j],
[ 0.00000000-0.70710678j, 0.00000000 0.70710678j]]))
Parameters:
square matrix
Returns
The eigenvalues, each repeated according to its multiplicity.
The normalized (unit 'length') eigenvectors, such that the
column ``v[:,i]`` is the eigenvector corresponding to the
eigenvalue ``w[i]`` . 矩陣類 這是一個關(guān)于矩陣類的簡短介紹。 >>> A = matrix('1.0 2.0; 3.0 4.0')
>>> A
[[ 1. 2.]
[ 3. 4.]]
>>> type(A) # file where class is defined
<class 'numpy.matrixlib.defmatrix.matrix'>
>>> A.T # transpose
[[ 1. 3.]
[ 2. 4.]]
>>> X = matrix('5.0 7.0')
>>> Y = X.T
>>> Y
[[5.]
[7.]]
>>> print A*Y # matrix multiplication
[[19.]
[43.]]
>>> print A.I # inverse
[[-2. 1. ]
[ 1.5 -0.5]]
>>> solve(A, Y) # solving linear equation
matrix([[-3.],
[ 4.]]) 索引:比較矩陣和二維數(shù)組 注意NumPy中數(shù)組和矩陣有些重要的區(qū)別。NumPy提供了兩個基本的對象:一個N維數(shù)組對象和一個通用函數(shù)對象。其它對象都是建構(gòu)在它們之上 的。特別的,矩陣是繼承自NumPy數(shù)組對象的二維數(shù)組對象。對數(shù)組和矩陣,索引都必須包含合適的一個或多個這些組合:整數(shù)標(biāo)量、省略號 (ellipses)、整數(shù)列表;布爾值,整數(shù)或布爾值構(gòu)成的元組,和一個一維整數(shù)或布爾值數(shù)組。矩陣可以被用作矩陣的索引,但是通常需要數(shù)組、列表或者 其它形式來完成這個任務(wù)。 現(xiàn)在有些和Python索引不同的了:你可以同時使用逗號分割索引來沿著多個軸索引。 >>> print A[:,1]; print A[:,1].shape
[1 5 9]
(3,)
>>> print M[:,1]; print M[:,1].shape
[[1]
[5]
[9]]
(3, 1) >>> A[:,[1,3]]
array([[ 1, 3],
[ 5, 7],
[ 9, 11]]) 稍微復(fù)雜點的方法是使用 >>> A[:,].take([1,3],axis=1)
array([[ 1, 3],
[ 5, 7],
[ 9, 11]]) 如果我們想跳過第一行,我們可以這樣: >>> A[1:,].take([1,3],axis=1)
array([[ 5, 7],
[ 9, 11]]) 或者我們僅僅使用 >>> A[ix_((1,2),(1,3))]
array([[ 5, 7],
[ 9, 11]]) 為了讀者的方便,在次寫下之前的矩陣: >>> A[ix_((1,2),(1,3))]
array([[ 5, 7],
[ 9, 11]]) 現(xiàn)在讓我們做些更復(fù)雜的。比如說我們想要保留第一行大于1的列。一種方法是創(chuàng)建布爾索引: >>> A[0,:]>1
array([False, False, True, True], dtype=bool)
>>> A[:,A[0,:]>1]
array([[ 2, 3],
[ 6, 7],
[10, 11]]) 就是我們想要的!但是索引矩陣沒這么方便。 >>> M[0,:]>1
matrix([[False, False, True, True]], dtype=bool)
>>> M[:,M[0,:]>1]
matrix([[2, 3]]) 技巧和提示 下面我們給出簡短和有用的提示。 “自動”改變形狀 更改數(shù)組的維度,你可以省略一個尺寸,它將被自動推導(dǎo)出來。 >>> a = arange(30)
>>> a.shape = 2,-1,3 # -1 means 'whatever is needed'
>>> a.shape
(2, 5, 3)
>>> a
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]]]) 2 NumPy-快速處理數(shù)據(jù)標(biāo)準(zhǔn)安裝的Python中用列表(list)保存一組值,可以用來當(dāng)作數(shù)組使用,不過由于列表的元素可以是任何對象,因此列表中所保存的是對象的指針。這樣為了保存一個簡單的[1,2,3],需要有3個指針和三個整數(shù)對象。對于數(shù)值運(yùn)算來說這種結(jié)構(gòu)顯然比較浪費(fèi)內(nèi)存和CPU計算時間。 此外Python還提供了一個array模塊,array對象和列表不同,它直接保存數(shù)值,和C語言的一維數(shù)組比較類似。但是由于它不支持多維,也沒有各種運(yùn)算函數(shù),因此也不適合做數(shù)值運(yùn)算。 NumPy的誕生彌補(bǔ)了這些不足,NumPy提供了兩種基本的對象:ndarray(N-dimensional array object)和 ufunc(universal function object)。ndarray(下文統(tǒng)一稱之為數(shù)組)是存儲單一數(shù)據(jù)類型的多維數(shù)組,而ufunc則是能夠?qū)?shù)組進(jìn)行處理的函數(shù)。 數(shù)組的大小可以通過其shape屬性獲得: >>> a.shape(4,)>>> c.shape(3, 4) 數(shù)組a的shape只有一個元素,因此它是一維數(shù)組。而數(shù)組c的shape有兩個元素,因此它是二維數(shù)組,其中第0軸的長度為3,第1軸的長度為4。還可以通過修改數(shù)組的shape屬性,在保持?jǐn)?shù)組元素個數(shù)不變的情況下,改變數(shù)組每個軸的長度。下面的例子將數(shù)組c的shape改為(4,3),注意從(3,4)改為(4,3)并不是對數(shù)組進(jìn)行轉(zhuǎn)置,而只是改變每個軸的大小,數(shù)組元素在內(nèi)存中的位置并沒有改變: 數(shù)組的元素類型可以通過dtype屬性獲得。上面例子中的參數(shù)序列的元素都是整數(shù),因此所創(chuàng)建的數(shù)組的元素類型也是整數(shù),并且是32bit的長整型??梢酝ㄟ^dtype參數(shù)在創(chuàng)建時指定元素類型: >>> np.array([[1, 2, 3, 4],[4, 5, 6, 7], [7, 8, 9, 10]], dtype=np.float)array([[ 1., 2., 3., 4.], [ 4., 5., 6., 7.], [ 7., 8., 9., 10.]])>>> np.array([[1, 2, 3, 4],[4, 5, 6, 7], [7, 8, 9, 10]], dtype=np.complex)array([[ 1. 0.j, 2. 0.j, 3. 0.j, 4. 0.j], [ 4. 0.j, 5. 0.j, 6. 0.j, 7. 0.j], [ 7. 0.j, 8. 0.j, 9. 0.j, 10. 0.j]]) 上面的例子都是先創(chuàng)建一個Python序列,然后通過array函數(shù)將其轉(zhuǎn)換為數(shù)組,這樣做顯然效率不高。因此NumPy提供了很多專門用來創(chuàng)建數(shù)組的函數(shù)。下面的每個函數(shù)都有一些關(guān)鍵字參數(shù),具體用法請查看函數(shù)說明。
使用布爾數(shù)組 當(dāng)使用布爾數(shù)組b作為下標(biāo)存取數(shù)組x中的元素時,將收集數(shù)組x中所有在數(shù)組b中對應(yīng)下標(biāo)為True的元素。使用布爾數(shù)組作為下標(biāo)獲得的數(shù)組不和原始數(shù)組共享數(shù)據(jù)空間,注意這種方式只對應(yīng)于布爾數(shù)組,不能使用布爾列表。 .1.3 多維數(shù)組 多維數(shù)組的存取和一維數(shù)組類似,因為多維數(shù)組有多個軸,因此它的下標(biāo)需要用多個值來表示,NumPy采用組元(tuple)作為數(shù)組的下標(biāo)。如圖2.1所示,a為一個6x6的數(shù)組,圖中用顏色區(qū)分了各個下標(biāo)以及其對應(yīng)的選擇區(qū)域。 組元不需要圓括號 雖然我們經(jīng)常在Python中用圓括號將組元括起來,但是其實組元的語法定義只需要用逗號隔開即可,例如 x,y=y,x 就是用組元交換變量值的一個例子。
2.1.4 結(jié)構(gòu)數(shù)組 在C語言中我們可以通過struct關(guān)鍵字定義結(jié)構(gòu)類型,結(jié)構(gòu)中的字段占據(jù)連續(xù)的內(nèi)存空間,每個結(jié)構(gòu)體占用的內(nèi)存大小都相同,因此可以很容易地定義結(jié)構(gòu)數(shù)組。和C語言一樣,在NumPy中也很容易對這種結(jié)構(gòu)數(shù)組進(jìn)行操作。只要NumPy中的結(jié)構(gòu)定義和C語言中的定義相同,NumPy就可以很方便地讀取C語言的結(jié)構(gòu)數(shù)組的二進(jìn)制數(shù)據(jù),轉(zhuǎn)換為NumPy的結(jié)構(gòu)數(shù)組。 假設(shè)我們需要定義一個結(jié)構(gòu)數(shù)組,它的每個元素都有name, age和weight字段。在NumPy中可以如下定義 內(nèi)存對齊 C語言的結(jié)構(gòu)體為了內(nèi)存尋址方便,會自動的添加一些填充用的字節(jié),這叫做內(nèi)存對齊。例如如果把下面的name[32]改為name[30]的話,由于內(nèi)存對齊問題,在name和age中間會填補(bǔ)兩個字節(jié),最終的結(jié)構(gòu)體大小不會改變。因此如果numpy中的所配置的內(nèi)存大小不符合C語言的對齊規(guī)范的話,將會出現(xiàn)數(shù)據(jù)錯位。為了解決這個問題,在創(chuàng)建dtype對象時,可以傳遞參數(shù)align=True,這樣numpy的結(jié)構(gòu)數(shù)組的內(nèi)存對齊和C語言的結(jié)構(gòu)體就一致了。 用下面的字典參數(shù)也可以定義結(jié)構(gòu)類型,字典的關(guān)鍵字為結(jié)構(gòu)中字段名,值為字段的類型描述,但是由于字典的關(guān)鍵字是沒有順序的,因此字段的順序需要在類型描述中給出,類型描述是一個組元,它的第二個值給出字段的字節(jié)為單位的偏移量,例如age字段的偏移量為25個字節(jié): >>> np.dtype({'surname':('S25',0),'age':(np.uint8,25)})dtype([('surname', '|S25'), ('age', '|u1')]) 2.1.5 內(nèi)存結(jié)構(gòu) 下面讓我們來看看ndarray數(shù)組對象是如何在內(nèi)存中儲存的。如圖2.3所示,關(guān)于數(shù)組的描述信息保存在一個數(shù)據(jù)結(jié)構(gòu)中,這個結(jié)構(gòu)引用兩個對象:一塊用于保存數(shù)據(jù)的存儲區(qū)域和一個用于描述元素類型的dtype對象。 sin函數(shù)的第二個參數(shù)也是x,那么它所做的事情就是對x中的每給值求正弦值,并且把結(jié)果保存到x中的對應(yīng)的位置中。此時函數(shù)的返回值仍然是整個計算的結(jié)果,只不過它就是x,因此兩個變量的id是相同的(變量t和變量x指向同一塊內(nèi)存區(qū)域)。 我用下面這個小程序,比較了一下numpy.math和Python標(biāo)準(zhǔn)庫的math.sin的計算速度:: 請注意numpy.sin的計算速度只有math.sin的1/5。這是因為numpy.sin為了同時支持?jǐn)?shù)組和單個值的計算,其C語言的內(nèi)部實現(xiàn)要比math.sin復(fù)雜很多,如果我們同樣在Python級別進(jìn)行循環(huán)的話,就會看出其中的差別了。此外,numpy.sin返回的數(shù)的類型和math.sin返回的類型有所不同,math.sin返回的是Python的標(biāo)準(zhǔn)float類型,而numpy.sin則返回一個numpy.float64類型: 由于Python的操作符重載功能,計算兩個數(shù)組相加可以簡單地寫為a b,而np.add(a,b,a)則可以用a =b來表示。下面是數(shù)組的運(yùn)算符和其對應(yīng)的ufunc函數(shù)的一個列表,注意除號'/'的意義根據(jù)是否激活__future__.division有所不同。
值得注意的是用frompyfunc得到的函數(shù)計算出的數(shù)組元素的類型為object,因為frompyfunc函數(shù)無法保證Python函數(shù)返回的數(shù)據(jù)類型都完全一致。因此還需要再次 y2.astype(np.float64)將其轉(zhuǎn)換為雙精度浮點數(shù)組。 2.2.1 廣播 當(dāng)我們使用ufunc函數(shù)對兩個數(shù)組進(jìn)行計算時,ufunc函數(shù)會對這兩個數(shù)組的對應(yīng)元素進(jìn)行計算,因此它要求這兩個數(shù)組有相同的大小(shape相同)。如果兩個數(shù)組的shape不同的話,會進(jìn)行如下的廣播(broadcasting)處理:
上述4條規(guī)則理解起來可能比較費(fèi)勁,讓我們來看一個實際的例子。 先創(chuàng)建一個二維數(shù)組a,其shape為(6,1): 這樣加法運(yùn)算的兩個輸入數(shù)組的shape分別為(6,1)和(1,5),根據(jù)規(guī)則2,輸出數(shù)組的各個軸的長度為輸入數(shù)組各個軸上的長度的最大值,可知輸出數(shù)組的shape為(6,5)。 由于b的第0軸上的長度為1,而a的第0軸上的長度為6,因此為了讓它們在第0軸上能夠相加,需要將b在第0軸上的長度擴(kuò)展為6,這相當(dāng)于: ogrid是一個很有趣的對象,它像一個多維數(shù)組一樣,用切片組元作為下標(biāo)進(jìn)行存取,返回的是一組可以用來廣播計算的數(shù)組。其切片下標(biāo)有兩種形式:
.2.2 ufunc的方法 ufunc函數(shù)本身還有些方法,這些方法只對兩個輸入一個輸出的ufunc函數(shù)有效,其它的ufunc對象調(diào)用這些方法時會拋出ValueError異常。 reduce 方法和Python的reduce函數(shù)類似,它沿著axis軸對array進(jìn)行操作,相當(dāng)于將<op>運(yùn)算符插入到沿axis軸的所有子數(shù)組或者元素當(dāng)中。 <op>.reduce (array=, axis=0, dtype=None) 例如: if indices[i] < indices[i 1]:
result[i] = np.reduce(a[indices[i]:indices[i 1]])
else:
result[i] = a[indices[i] 而最后一個元素如下計算: np.reduce(a[indices[-1]:]) 因此上面例子中,結(jié)果的每個元素如下計算而得: 2.3 矩陣運(yùn)算 NumPy和Matlab不一樣,對于多維數(shù)組的運(yùn)算,缺省情況下并不使用矩陣運(yùn)算,如果你希望對數(shù)組進(jìn)行矩陣運(yùn)算的話,可以調(diào)用相應(yīng)的函數(shù)。 matrix對象 numpy庫提供了matrix類,使用matrix類創(chuàng)建的是矩陣對象,它們的加減乘除運(yùn)算缺省采用矩陣方式計算,因此用法和matlab十分類似。但是由于NumPy中同時存在ndarray和matrix對象,因此用戶很容易將兩者弄混。這有違Python的“顯式優(yōu)于隱式”的原則,因此并不推薦在較復(fù)雜的程序中使用matrix。下面是使用matrix的一個例子: 使用numpy.savetxt和numpy.loadtxt可以讀寫1維和2維的數(shù)組: |
|