天天看點

NumPy的詳細教程

在閱讀這個教程之前,你多少需要知道點Python。如果你想從新回憶下,請看看Python Tutorial.

如果你想要運作教程中的示例,你至少需要在你的電腦上安裝了以下一些軟體:

Python

NumPy

這些是可能對你有幫助的:

ipython是一個淨強化的互動Python Shell,對探索NumPy的特性非常友善。

matplotlib将允許你繪圖

Scipy在NumPy的基礎上提供了很多科學子產品

NumPy的主要對象是同種元素的多元數組。這是一個所有的元素都是一種類型、通過一個正整數元組索引的元素表格(通常是元素是數字)。在NumPy中次元(dimensions)叫做軸(axes),軸的個數叫做秩(rank)。

例如,在3D空間一個點的坐标<code>[1, 2, 3]</code>是一個秩為1的數組,因為它隻有一個軸。那個軸長度為3.又例如,在以下例子中,數組的秩為2(它有兩個次元).第一個次元長度為2,第二個次元長度為3.

NumPy的數組類被稱作ndarray。通常被稱作數組。注意numpy.array和标準Python庫類array.array并不相同,後者隻處理一維數組和提供少量功能。更多重要ndarray對象屬性有:

ndarray.ndim

數組軸的個數,在python的世界中,軸的個數被稱作秩

ndarray.shape

數組的次元。這是一個訓示數組在每個次元上大小的整數元組。例如一個n排m列的矩陣,它的shape屬性将是(2,3),這個元組的長度顯然是秩,即次元或者ndim屬性

ndarray.size

數組元素的總個數,等于shape屬性中元組元素的乘積。

ndarray.dtype

一個用來描述數組中元素類型的對象,可以通過創造或指定dtype使用标準Python類型。另外NumPy提供它自己的資料類型。

ndarray.itemsize

數組中每個元素的位元組大小。例如,一個元素類型為float64的數組itemsiz屬性值為8(=64/8),又如,一個元素類型為complex32的數組item屬性為4(=32/8).

ndarray.data

包含實際數組元素的緩沖區,通常我們不需要使用這個屬性,因為我們總是通過索引來使用數組中的元素。

有好幾種建立數組的方法。

例如,你可以使用<code>array</code>函數從正常的Python清單和元組創造數組。所建立的數組類型由原序列中的元素類型推導而來。

數組将序列包含序列轉化成二維的數組,序列包含序列包含序列轉化成三維數組等等。

數組類型可以在建立時顯示指定

通常,數組的元素開始都是未知的,但是它的大小已知。是以,NumPy提供了一些使用占位符建立數組的函數。這最小化了擴充數組的需要和高昂的運算代價。

函數<code>function</code>建立一個全是0的數組,函數<code>ones</code>建立一個全1的數組,函數<code>empty</code>建立一個内容随機并且依賴與記憶體狀态的數組。預設建立的數組類型(dtype)都是float64。

為了建立一個數列,NumPy提供一個類似arange的函數傳回數組而不是清單:

當<code>arange</code>使用浮點數參數時,由于有限的浮點數精度,通常無法預測獲得的元素個數。是以,最好使用函數<code>linspace</code>去接收我們想要的元素個數來代替用range來指定步長。

其它函數array, zeros, zeros_like, ones, ones_like, empty, empty_like, arange, linspace, rand, randn, fromfunction, fromfile參考:NumPy示例

當你列印一個數組,NumPy以類似嵌套清單的形式顯示它,但是呈以下布局:

最後的軸從左到右列印

次後的軸從頂向下列印

剩下的軸從頂向下列印,每個切片通過一個空行與下一個隔開

一維數組被列印成行,二維數組成矩陣,三維數組成矩陣清單。

檢視形狀操作一節獲得有關reshape的更多細節

如果一個數組用來列印太大了,NumPy自動省略中間部分而隻列印角落

禁用NumPy的這種行為并強制列印整個數組,你可以設定printoptions參數來更改列印選項。

數組的算術運算是按元素的。新的數組被建立并且被結果填充。

不像許多矩陣語言,NumPy中的乘法運算符<code>*</code>訓示按元素計算,矩陣乘法可以使用<code>dot</code>函數或建立矩陣對象實作(參見教程中的矩陣章節)

有些操作符像<code>+=</code>和<code>*=</code>被用來更改已存在數組而不建立一個新的數組。

當運算的是不同類型的數組時,結果數組和更普遍和精确的已知(這種行為叫做upcast)。

這些運算預設應用到數組好像它就是一個數字組成的清單,無關數組的形狀。然而,指定<code>axis</code>參數你可以吧運算應用到數組指定的軸上:

NumPy提供常見的數學函數如<code>sin</code>,<code>cos</code>和<code>exp</code>。在NumPy中,這些叫作“通用函數”(ufunc)。在NumPy裡這些函數作用按數組的元素運算,産生一個數組作為輸出。

更多函數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 參見:NumPy示例

一維數組可以被索引、切片和疊代,就像清單和其它Python序列。

多元數組可以每個軸有一個索引。這些索引由一個逗号分割的元組給出。

當少于軸數的索引被提供時,确失的索引被認為是整個切片:

<code>b[i]</code>中括号中的表達式被當作<code>i</code>和一系列<code>:</code>,來代表剩下的軸。NumPy也允許你使用“點”像<code>b[i,...]</code>。

點(…)代表許多産生一個完整的索引元組必要的分号。如果x是秩為5的數組(即它有5個軸),那麼:

x[1,2,…] 等同于 x[1,2,:,:,:],

x[…,3] 等同于 x[:,:,:,:,3]

x[4,…,5,:] 等同 x[4,:,:,5,:].

疊代多元數組是就第一個軸而言的:2

然而,如果一個人想對每個數組中元素進行運算,我們可以使用flat屬性,該屬性是數組元素的一個疊代器:

更多[], …, newaxis, ndenumerate, indices, index exp 參考NumPy示例

一個數組的形狀由它每個軸上的元素個數給出:

一個數組的形狀可以被多種指令修改:

由<code>ravel()</code>展平的數組元素的順序通常是“C風格”的,就是說,最右邊的索引變化得最快,是以元素a[0,0]之後是a[0,1]。如果數組被改變形狀(reshape)成其它形狀,數組仍然是“C風格”的。NumPy通常建立一個以這個順序儲存資料的數組,是以<code>ravel()</code>将總是不需要複制它的參數3。但是如果數組是通過切片其它數組或有不同尋常的選項時,它可能需要被複制。函數<code>reshape()</code>和<code>ravel()</code>還可以被同過一些可選參數建構成FORTRAN風格的數組,即最左邊的索引變化最快。

<code>reshape</code>函數改變參數形狀并傳回它,而<code>resize</code>函數改變數組自身。

如果在改變形狀操作中一個次元被給做-1,其次元将自動被計算

更多 shape, reshape, resize, ravel 參考NumPy示例

幾種方法可以沿不同軸将數組堆疊在一起:

函數<code>column_stack</code>以列将一維數組合成二維數組,它等同與<code>vstack</code>對一維數組。

<code>row_stack</code>函數,另一方面,将一維數組以行組合成二維數組。

對那些次元比二維更高的數組,<code>hstack</code>沿着第二個軸組合,<code>vstack</code>沿着第一個軸組合,<code>concatenate</code>允許可選參數給出組合時沿着的軸。

Note

在複雜情況下,<code>r_[]</code>和<code>c_[]</code>對建立沿着一個方向組合的數很有用,它們允許範圍符号(“:”):

當使用數組作為參數時,<code>r_</code>和<code>c_</code>的預設行為和<code>vstack</code>和<code>hstack</code>很像,但是允許可選的參數給出組合所沿着的軸的代号。

更多函數hstack , vstack, column_stack , row_stack , concatenate , c_ , r_ 參見NumPy示例.

使用<code>hsplit</code>你能将數組沿着它的水準軸分割,或者指定傳回相同形狀數組的個數,或者指定在哪些列後發生分割:

<code>vsplit</code>沿着縱向的軸分割,<code>array split</code>允許指定沿哪個軸分割。

當運算和處理數組時,它們的資料有時被拷貝到新的數組有時不是。這通常是新手的困惑之源。這有三種情況:

簡單的指派不拷貝數組對象或它們的資料。

Python 傳遞不定對象作為參考4,是以函數調用不拷貝數組。

不同的數組對象分享同一個資料。視圖方法創造一個新的數組對象指向同一資料。

切片數組傳回它的一個視圖:

這個複制方法完全複制數組和它的資料。

這是個NumPy函數和方法分類排列目錄。這些名字連結到NumPy示例,你可以看到這些函數起作用。[^5]

建立數組

轉化

操作

詢問

排序

運算

基本統計

基本線性代數

廣播法則能使通用函數有意義地處理不具有相同形狀的輸入。

廣播第一法則是,如果所有的輸入數組次元不都相同,一個“1”将被重複地添加在次元較小的數組上直至所有的數組擁有一樣的次元。

廣播第二法則确定長度為1的數組沿着特殊的方向表現地好像它有沿着那個方向最大形狀的大小。對數組來說,沿着那個次元的數組元素的值理應相同。

應用廣播法則之後,所有數組的大小必須比對。更多細節可以從這個文檔找到。

NumPy比普通Python序列提供更多的索引功能。除了索引整數和切片,正如我們之前看到的,數組可以被整數數組和布爾數組索引。

當被索引數組a是多元的時,每一個唯一的索引數列指向a的第一維5。以下示例通過将圖檔标簽用調色版轉換成色彩圖像展示了這種行為。

我們也可以給出不不止一維的索引,每一維的索引數組必須有相同的形狀。

自然,我們可以把i和j放到序列中(比如說清單)然後通過list索引。

然而,我們不能把i和j放在一個數組中,因為這個數組将被解釋成索引a的第一維。

另一個常用的數組索引用法是搜尋時間序列最大值6。

你也可以使用數組索引作為目标來指派:

然而,當一個索引清單包含重複時,指派被多次完成,保留最後的值:

這足夠合理,但是小心如果你想用Python的<code>+=</code>結構,可能結果并非你所期望:

即使0在索引清單中出現兩次,索引為0的元素僅僅增加一次。這是因為Python要求<code>a+=1</code>和<code>a=a+1</code>等同。

當我們使用整數數組索引數組時,我們提供一個索引清單去選擇。通過布爾數組索引的方法是不同的我們顯式地選擇數組中我們想要和不想要的元素。

我們能想到的使用布爾數組的索引最自然方式就是使用和原數組一樣形狀的布爾數組。

這個屬性在指派時非常有用:

你可以參考曼德博集合示例看看如何使用布爾索引來生成曼德博集合的圖像。

第二種通過布爾來索引的方法更近似于整數索引;對數組的每個次元我們給一個一維布爾數組來選擇我們想要的切片。

注意一維數組的長度必須和你想要切片的次元或軸的長度一緻,在之前的例子中,b1是一個秩為1長度為三的數組(a的行數),b2(長度為4)與a的第二秩(列)相一緻。7

<code>ix_</code>函數可以為了獲得多元組的結果而用來結合不同向量。例如,如果你想要用所有向量a、b和c元素組成的三元組來計算<code>a+b*c</code>:

你也可以實行如下簡化:

然後這樣使用它:

這個reduce與ufunc.reduce(比如說add.reduce)相比的優勢在于它利用了廣播法則,避免了建立一個輸出大小乘以向量個數的參數數組。8

參見RecordArray。

繼續前進,基本線性代數包含在這裡。

參考numpy檔案夾中的linalg.py獲得更多資訊

這是一個關于矩陣類的簡短介紹。

注意NumPy中數組和矩陣有些重要的差別。NumPy提供了兩個基本的對象:一個N維數組對象和一個通用函數對象。其它對象都是建構在它們之上 的。特别的,矩陣是繼承自NumPy數組對象的二維數組對象。對數組和矩陣,索引都必須包含合适的一個或多個這些組合:整數标量、省略号 (ellipses)、整數清單;布爾值,整數或布爾值構成的元組,和一個一維整數或布爾值數組。矩陣可以被用作矩陣的索引,但是通常需要數組、清單或者 其它形式來完成這個任務。

像平常在Python中一樣,索引是從0開始的。傳統上我們用矩形的行和清單示一個二維數組或矩陣,其中沿着0軸的方向被穿過的稱作行,沿着1軸的方向被穿過的是列。9

讓我們建立數組和矩陣用來切片:

現在,讓我們簡單的切幾片。基本的切片使用切片對象或整數。例如,<code>A[:]</code>和<code>M[:]</code>的求值将表現得和Python索引很相似。然而要注意很重要的一點就是NumPy切片數組不建立資料的副本;切片提供統一資料的視圖。

現在有些和Python索引不同的了:你可以同時使用逗号分割索引來沿着多個軸索引。

注意最後兩個結果的不同。對二維數組使用一個冒号産生一個一維數組,然而矩陣産生了一個二維矩陣。10例如,一個<code>M[2,:]</code>切片産生了一個形狀為(1,4)的矩陣,相比之下,一個數組的切片總是産生一個最低可能次元11的數組。例如,如果C是一個三維數組,<code>C[...,1]</code>産生一個二維的數組而<code>C[1,:,1]</code>産生一個一維數組。從這時開始,如果相應的矩陣切片結果是相同的話,我們将隻展示數組切片的結果。

假如我們想要一個數組的第一列和第三列,一種方法是使用清單切片:

稍微複雜點的方法是使用<code>take()</code>方法(method):

如果我們想跳過第一行,我們可以這樣:

或者我們僅僅使用<code>A[1:,[1,3]]</code>。還有一種方法是通過矩陣向量積(叉積)。

為了讀者的友善,在次寫下之前的矩陣:

現在讓我們做些更複雜的。比如說我們想要保留第一行大于1的列。一種方法是建立布爾索引:

就是我們想要的!但是索引矩陣沒這麼友善。

這個過程的問題是用“矩陣切片”來切片産生一個矩陣12,但是矩陣有個友善的<code>A</code>屬性,它的值是數組呈現的。是以我們僅僅做以下替代:

如果我們想要在矩陣兩個方向有條件地切片,我們必須稍微調整政策,代之以:

我們需要使用向量積<code>ix_</code>:

下面我們給出簡短和有用的提示。

更改數組的次元,你可以省略一個尺寸,它将被自動推導出來。

我們如何用兩個相同尺寸的行向量清單建構一個二維數組?在MATLAB中這非常簡單:如果x和y是兩個相同長度的向量,你僅僅需要做<code>m=[x;y]</code>。在NumPy中這個過程通過函數<code>column_stack</code>、<code>dstack</code>、<code>hstack</code>和<code>vstack</code>來完成,取決于你想要在那個次元上組合。例如:

二維以上這些函數背後的邏輯會很奇怪。

參考寫個Matlab使用者的NumPy指南并且在這裡添加你的新發現: )

NumPy中<code>histogram</code>函數應用到一個數組傳回一對變量:直方圖數組和箱式向量。注意:<code>matplotlib</code>也有一個用來建立直方圖的函數(叫作<code>hist</code>,正如matlab中一樣)與NumPy中的不同。主要的差别是<code>pylab.hist</code>自動繪制直方圖,而<code>numpy.histogram</code>僅僅産生資料。