這系列用來介紹Python的標准庫的支持Numpy部分。資料來自http://wiki.scipy.org/Tentative_NumPy_Tutorial,頁面有許多鏈接,這里是直接翻譯,所以會無法鏈接。可以大致看完該博文,再去看英文版。
1、先決條件
想要運行numpy,首先最小安裝的有:Python、NumPy。:a、ipython 是一個增強的交互式python shell,它對於探索numpy的特性是非常方便的;b、matplotlib可以讓你進行plot 圖表;c、SciPy提供許多工作在numpy頂端的科學的例子。
2、基礎知識
numpy的主要對象是同質多維數組。也就是在一個元素(通常是數字)表中,元素的類型都是相同的。其中可以通過正整數的元組來對元素進行索引。在numpy中數組的維度被稱為軸(axes),軸的數量稱為秩(rank)。例如,在3維空間中一個點[1,2,1]的坐標就是秩為1的數組,因為它只有一個軸。這個軸的長度為3。下面的例子中,數組的秩為2(因為是2維的)。第一個維度(軸)的大小是2,第二個維度的大小是3:
numpy的數組類被成為ndarray。別名為array。numpy.array與標准python庫類array.array不一樣,標准庫類中的那個只能處理一維數組並且功能更少。ndarray對象的重要的屬性有:
ndarray.ndim:數組的軸(維度)的數量。在python中,維度的數量通常被稱為rank。
ndarray.shape:數組的維度。為一個整數元組,表示每個維度上的大小。對於一個n行m列的矩陣來說,shape就是(n,m)。shape元組的長度就是秩(或者維度的數量)ndim。
ndarray.size:數組的元素的總個數。這等於shape元素的乘積。
ndarray.dtype:用來描述數組中元素類型的對象。可以用標准python類型來創建或指定dtype;或者在后面,加上numpy的類型。numpy.int32;numpy.int16;numpy.float64等等
ndarray.itermsize:數組的每個元素的字節大小。例如,一個類型為float64的元素的數組itemsize 為8(=64/8),而一個complex32的數組itersize為4(=32/8)。該屬性等價於ndarray.dtype.itemsize。
ndarray.data:該緩沖區包含了數組的實際元素。通常情況下,我們不需要使用這個屬性,因為我們會使用索引的方式來訪問數組中的元素。
1)例子
2)構建數組
有幾種方法來構建數組。例如可以通過一個常規的python列表或者使用array函數的元組來構建。可以通過調用生成后數組的屬性dtype來了解該數組的元素類型:
經常犯得的錯誤:調用array的時候,傳遞了多個數值參數,而不是使用單一的數字列表:
array會將序列的序列轉換成2維的數組,序列的序列的序列會轉換成3維的數組,等等:
數組的類型同樣可以在創建的時侯顯式指定:
通常來說,數組中元素的值在開始的時候是未知的,不過數組的大小是已知的。所以numpy提供幾個函數在創建數組的時候對元素的值進行占位。這樣就可以避免后續需要對數組進行動態增長的操作(數組的動態增長的代價較大)。函數zeros生成一個全為0的數組;函數ones生成一個全為1的數組,函數empty生成一個初始化內容為隨機並且依賴於內存狀態的數組。默認情況下,生成的數組的dtype是float64:
為了生成數字序列。numpy提供一個類似於range的函數,返回一個列表,參數為(起始,結束,步長):
當傳遞的參數是浮點數時,因為浮點數精度是有限的,所以通常不會有穩定的元素個數的保證。所以,使用函數linspace是一個更好的選擇,因為我們可以對該函數指定需要創建多少個元素,參數為(起始,結束,元素個數):
see also:array, zeros, zeros_like, ones, ones_like, empty, empty_like, arange, linspace, rand, randn,fromfunction, fromfile
3)打印數組
當需要打印數組的時候,numpy通過類似列表嵌套的形式來顯示結果。其中的布局為:a、在數組的最后維度(軸)上,元素是從左到右打印的,比如下面,c的[8 9 10 11]:b、其他維度上都是自頂向下打印的;當維度較多時,每個分片之間通過一個空行隔開:一維數組按行打印,二維按矩陣打印,三維按矩陣的列表打印:
below更多信息可以查看reshape。如果一個數組太大以至於無法打印,numpy自動跳過中間部分只打印角部分:
如果想關閉該功能,並強制numpy打印整個數組,可以改變打印的選項:通過使用set_printoptions:
4)基本操作
在數組上的算術操作符是逐元素的elementwise。得到的是一個重新創建的數組,然后將結果寫入新數組中:
不同於其他的一些語言對矩陣的操作,在numpy中乘積操作符×是逐元素進行的。矩陣的積可以通過使用dot 函數或者創建matrix對象:
許多操作,例如+= 和×=,支持原處修改現有的數組,而不是生成一個新的數組:
當涉及到不同類型的數組時,是會將更通用或者精確度更高的那個類型(upcasting)作為新數組的類型:
例如計算數組中所有元素的和的這類一元運算都是以ndarray類的方法來實現的:
默認情況下,這些操作的前提是數組中的元素是數字。通過指定axie參數,可以指定對數組的哪個軸進行操作:
5)通用函數
numpy提供常見的數學函數,例如sin,cos,和exp。在numpy中,這些被稱為“通用函數 universal functions(ufunc)”。在numpy中,這些函數是逐元素操作的,輸出的就是新的數組:
see also:all, alltrue, any, apply along axis, argmax, argmin, argsort, average, bincount, ceil, clip, conj, conjugate, corrcoef, cov, cross, cumprod, cumsum, diff, dot, floor, inner, inv, lexsort, max, maximum, mean, median, min, minimum, nonzero, outer, prod, re, round, sometrue, sort, std,sum, trace, transpose, var, vdot, vectorize, where
6)索引,分片和迭代
一維數組可以被索引,分片和迭代。就像列表和其它python序列一樣:
多維數組可以每個軸都有一個索引,通過逗號隔開的元組來指定不同的軸上的索引操作:
如果提供的索引比軸的個數要少,缺省的索引表示的軸上會被認為是一個完整的分片:
放在括號中的表達式b【i】表示一個i 后面跟着許多的值:根據需要來表示其他的軸,numpy同樣可以使用三個點省略:點(...)表示根據需要來代替未指定的軸的所有元素的索引。例如。如果x 是秩為5的數組(即有5個軸),那么
基於多維數組的迭代只是在第一個軸上進行操作(也就是最上層的軸):
然而如果想要在數組中每個元素上都有操作,需要使用flat屬性,這是基於數組所有元素的一個迭代器( iterator ):
see also:[], ..., newaxis, ndenumerate, indices, index exp
3、形狀操作
1)改變數組的形狀
當指定數組每個軸上元素個數的時候,就形成了shape:
數組的shape可以通過其他命令來改變:
從ravel()中生成的數組中元素的順序是標准的“C-風格”,也就是,最右邊的索引“改變的最快”。所以元素a【0,0】之后就是a【0,1】.如果數字是被reshaped到一些其他的shape,該數組還是被認為“C-風格”。numpy通常生成的數組都是這種順序存儲的,所以ravel()不需要復制它的參數,不過如果數組是通過另一個數組的分片或者不平常的選項生成的,它也許需要被復制。函數ravel()和reshape()可以通過一個選項參數來指定是否使用FORTRAN-style的存儲,即最左邊的索引變得最快。reshape函數返回的是修改過的shape的參數,因而 resize方法會修改數組本身:
如果在reshape操作中,某個維度的值為-1,那么就會被自動計算
see also:shape example, reshape example, resize example, ravel example
2)將不同的數組堆疊在一起
可以在不同的軸上將幾個數組堆疊起來:
函數column_stack 可以將1維數組按列的方式堆疊成2維的數組(下圖第5個命令)。注意下面的vstack函數:
另一方面,函數 row_stack,按照行的方式將1維數組堆疊成2維數組。對於超過2維的數組,hstack會沿着第二軸進行堆疊,vstack會沿着第一軸堆疊, concatenate允許一個可選的參數,指定在第幾個軸上進行concatenation操作。
Note:在復數情況中,r_[] 和c_[] 可以如下來生成數組。它們允許范圍標識(“:”)的使用:
當將數組作為參數使用時,r_[] 和c_[] 的操作類似於vstack和 hstack在默認參數下的結果,同時也可以通過一個可選參數來指定連接(concatenate)哪個軸。
see also:hstack example, vstack exammple, column_stack example, row_stack example,concatenate example, c_ example, r_ example。
3)將一個數組划分成幾個小的數組
使用hsplit函數,可以沿着水平軸划分數組。可以進行等同划分,或者指定列划分:
vsplit沿着豎直軸進行划分,array split 允許指定沿着哪個軸划分。
4、復制和視圖
當對數組進行操作的時候,它們的數據有時候會被復制到一個新的數組中,有時候又不會。這通常是一個對於初學者來說很困惑的地方。有三種情況:
1)完全不復制
簡單的賦值不會復制數組對象或者它們的數值:
python將可變的對象作為引用,所以函數調用是沒有復制的:
2)淺層復制
不同的數組對象可以共享相同的數據。view方法生成一個新的數組對象,其中的數據看上去是一樣的:
3)深層復制
copy方法會生成一個數組和它的數據的復制版本:
4)函數和方法概述
這里列出numpy的函數列表和方法。名字是與Numpy Example List相關聯的:
創建數組:arange, array, copy, empty, empty_like, eye, fromfile, fromfunction, identity, linspace, logspace, mgrid, ogrid, ones, ones_like, r , zeros, zeros_like
轉換:astype, atleast 1d, atleast 2d, atleast 3d, mat。
操作(manipulations):array split, column stack, concatenate, diagonal, dsplit, dstack, hsplit, hstack, item, newaxis,ravel, repeat, reshape, resize, squeeze, swapaxes, take, transpose, vsplit, vstack
排序:argmax, argmin, argsort, max, min, ptp, searchsorted, sort。
操作(operations):choose, compress, cumprod, cumsum, inner, fill, imag, prod, put, putmask, real, sum
基本的線性代數:cross, dot, outer, svd, vdot。
5、更少的基礎
1)廣播(broadcasting)的規則
廣播允許通用函數中的矩陣的shape不完全一致:a、廣播的第一個規則就是如果所有的輸入數組沒有相同數量的維度,“1”會被重復的預考慮到更小的數組的形狀上,直到所有的數組有着相同的維度數量;b、廣播的第二個規則就是確保有着size為1的數組可以沿着特定的維度進行操作,就好像沿着這個維度上數組有着最大的形狀(shape)。數組元素的值被假設成沿着這個維度有着一樣的“廣播”數組(個人:這里和matlab中bsxfun的行為類似)。在廣播規則的應用之后,所有的數組的size必須可以匹配。更多的可以查看 this documentation。
6、索引技巧
numpy提供比常規python序列更多的索引方法。除了整合和分片,數組可以被整數數組和布爾數組索引。
1)索引數組的索引
當索引數組是多維度的時候,索引數組中的每個值指向的是原來數組中的第一維(也就是頂層)。下面例子就是,image(2*4)索引的是palette(5*3的矩陣)中第一維上不同的子數組,結果為2*4*3的矩陣:
下面就是給出多個索引數組,這時候每個索引數組必須shape一致,這時候可以看成是坐標點的形式:
當然,我們可以將i 和 j 放入一個序列中(一個列表)然后對該列表進行索引:
然而,我們沒法將 i 和 j 放入數組中,因為這個數組會被解釋成 a 的第一維索引:
下面是另一個使用索引數組的例子:
可以使用索引數組來對指定元素進行更新:
然而,當索引的列表里面有重復的時候,同一個元素會被更新好幾次,並保留最后的更新:
當想要使用python的+=來構建的時候,它的結果也許不像你期望的那樣(沒有重復更新):
即使0在索引列表中發生了兩次。第0個元素只更新一次。這是因為python要求“a+=1”等效於“a = a+1”.
2)布爾數組的索引
當我們通過索引(整數)數組來對數組進行索引,我們提供了索引的列表去進行挑選,顯式的選擇數組中的項是否是我們想要的。對布爾索引的最自然的方式就是使用與原始數組一樣shape的布爾數組:
這個特性在賦值的時候很有用:
可以通過查看Mandelbrot set example來了解如何使用布爾索引來生成 Mandelbrot set的圖像的。
第二種布爾索引的方式更類似於整數索引,對於數組的每一維來說,我們給它一個1維布爾數組來選擇我們想要的分片:
注意到1維布爾數組的長度必須與你想要分片的維度(或者軸)的長度一致。在之前的例子中,b1 是一個 1-rank 的數組,長度為3(在a 中行的數量),和b2 (長度為4)是匹配a 的第二個秩(列)的索引的。
3)ix_()函數
ix_function可以組合不同維度的向量,然后按照參數的個數來決定進行多少維度的升級,下面是三個參數,所以ax有三維,如果是四個參數,那么ax就是四維了。例如,按照式子a+b*c來計算向量a,b,c 的所有元素的組合,得到的是一個4*3*5的矩陣:
或者定義函數:
然后像下面這樣使用:
與ufunc.reduce(numpy中的方法)相比較,該版本的優勢在於它會使用廣播規則( Broadcasting Rules)來避免生成參數數組等。
4)字符串的索引
7、線性代數
基本的線性代數都包含在這里。
1)單一數組操作
numpy的文件夾內的linalg.py的代碼可以更細致的介紹原理:
2)矩陣類
對矩陣類的簡短介紹:
3)索引:矩陣和2D數組的比較
注意到在NumPy 數組和矩陣之間不同的。NumPy 提供了兩種基本的對象:一個N維的數組對象和一個通用的函數對象。其他對象都是建立在這些上面的。特別的,矩陣是2維的數組對象,繼承自NumPy 數組對象。對於數組和矩陣來說,索引必須包含合適的一個或多個的組合:整數標量、省略號、整數或布爾值列表、整數或布爾值元組、整數或布爾值的1維數組。一個矩陣可以用來作為矩陣的索引,但是通常的數組、列表或其他的形式需要在給定的任務下完成。
在python中,索引是從0開始的。傳統的,我們將一個2D數組或矩陣表示成使用行和列的常規數組,沿着軸0移動就是沿着行移動,沿着軸1移動就是沿着列移動。
如下例子:
現在,讓我們考慮一些簡單的分片。基本的分片使用分片對象或者整數。例如,A[:]和M[:]在python中很相似,然而必須注意到分片Numpy數組不是對數據進行拷貝;分片提供對同一個數據的一個新的視圖:
現在,對於python索引中的一些不同,你也許會使用逗號隔開的索引對多個軸進行索引:
注意到上面兩個結果的不同。使用一個2D數組的復制會生成一個1維的數組,而對於一個矩陣來說,會生成一個2維的數組。一個矩陣的分片總是會生成一個矩陣。例如,一個分片M[2,:]生成一個shape(1,4)的矩陣。相反地,一個數組的分片總是生成一個最低可能維度的數組。例如,如果C是一個3維的數組,C[...,1]生成一個2D數組,同時C[1,...,1]會生成一個1維數組。我們顯示的結果就能看出在數組分片的結果和對應的矩陣分片的結果是不一樣的。
這里假設我們想要數組的第一和第三列。一種分片的方法是使用列表:
較為老練的方法是使用take()方法:
如果我們想要跳過第一行,我們可以:
或者簡單的使用A[1:,[1,3]]。然而,另一個方法是使用交叉結果:
為了讀者的方便,再次打印數組:
現在,讓我們做一些更復雜的事情。假設我們想要保留所有的那些第一行大於1的列。一種方法是生成一個布爾索引:
正如我們想要的!但是索引矩陣不是很方便:
問題就是分片矩陣的塊會生成一個矩陣。但是矩陣有一個方便的“A”屬性,它的值就是數組的表征,所以我們可以如下:
如果想要有條件的在兩個方向上分片矩陣。如下:
需要使用交叉積(cross product)“ix_”:
8、技巧和提示
這里給出一些短的但是有用的提示。
1)“自動”reshaping
使用-1可以讓機器自己計算該維度上是多少:
2)向量堆疊
如何從一個相同size的行向量列表中構建一個2D數組?在matlab中這是相當容易的:如果 x 和 y 是兩個有着相同大小的向量,你只需要 m = [x:y]就行。在Numpy中這是通過函數 column_stack, dstack, hstack 和 vstack,取決於哪個維度上的需要被堆疊。例如:
在超過2維情況下這些函數背后的邏輯是相當奇怪的。可以詳細的觀看 NumPy for Matlab Users 。
3)直方圖
應用在一個數組上的numpy的histogram函數會返回一個向量對:數組的直方圖和bins的向量。注意:matplotlib同樣有個函數來建立直方圖(叫做hist,和matlab中一樣)這不同於numpy中的這個函數。主要的區別在於pylab.hist會自動畫直方圖,而numpy.histogram只是生成數據:
9、參考資料
-
The Python tutorial.
-
The Numpy Example List.
-
The nonexistent NumPy Tutorial at scipy.org, where we can find the old Numeric documentation.
-
The Guide to NumPy book.
-
The SciPy Tutorial and a SciPy course online