numpy 快速入門
這是一篇能讓你10分鐘就入門numpy的快速教程。
===================================================================================================================================================================================================================================================================================
1.安裝
老規矩
pip install numpy
在程式碼中使用numpy,習慣上這樣引入
import numpy as np
直接import numpy或者as成別的東西也可以,但習慣上還是用上面的方法。此外,不要試圖from numpy import *,這會引起名稱衝突,也不好除錯。
2. 基本概念
numpy的最基本的資料型別是ndarray,它是多維陣列的一種表示方法。為了提升B格,也可以用『張量』稱呼它。用array函式就能夠建立一個ndarray,比如說:
a = np.array(1) b = np.array([1,2]) c = np.array([[1.0,2.0,3.0],[3.0,4.0,5.0]])
這裡,a實際上還是一個數,或者叫它『0階張量』。b是個向量,或者叫它『1階張量』。c是個矩陣,或者叫它『2階張量』。ndarray的深度,或者說張量的階數可以用其ndim屬性得到,每一階的長度可以用其shape屬性得到。shape屬性是一個tuple,其長度總是等於ndim。例如
print(a.ndim,a.shape) #0 () print(b.ndim,b.shape) #1 (2,) print(c.ndim,c.shape) #2 (2,3)
可以使用np.ones、np.zero、np.empty建立全0、全1和未初始化數字的ndarray。建立的時候要指定shape
print(np.ones(shape=(2,2))) # [[1,1],[1,1]]
使用中括號操作符可以得到ndarray的分量。經過中括號操作符,如果得到了維度不為0的分量,那麼這個分量的型別也是ndarray。如果得到的分量維度為0,則其型別為數字而不是維度為0的ndarray。這樣設計應該是為了計算方便。
d = c[0] print(d,d.ndim,d.shape) # [1.0,2.0,3.0] 1 (3,) e = c[1][2] print(e,type(e)) # 4.0 numpy.float64
習慣上,分量和維度從高維度算起。比如c作為一個2維陣列,c[0]的讀法是:『第1個維度的第1個分量』,或者『第1個維度的索引為0的分量』。
ndarray的維度方向的索引稱為『軸』(axis)
3. 數學計算
兩個shape相同的ndarray可以使用python的原生數學計算操作進行計算,這個計算過程是逐個元素對應進行的,得到的結果也是一個相同shape的ndarray
f = np.array([[10.0,20.0,30.0],[30.0,40.0,50.0]]) g = f + c print(g) #[[11.0,22.0,33.0],[33.0,44.0,55.0]]
一個普通的數字也能夠和ndarray使用原生資料計算操作計算,該數字將與ndarray的每個元素進行相同的計算。結果是一個同尺寸的ndarray
h = c * 3 print(h) #[[3.0,6.0,9.0],[9.0,12.0,15.0]]
python內建的數學函式不能直接使用,而是要使用numpy對應版本的函式。比如說,python的abs函式不能用於ndarray,要計算abs,得使用np.abs函式。這也是開頭不建議使用from numpy import *的原因。
i = np.abs(c-3) print(i) # [[2., 1., 0.],[0., 1., 2.]]
python的math模組的數學函式也不能直接使用,numpy同樣提供了相應版本的函式。
j = np.sin(i) print(j) # [[0.90929743, 0.84147098, 0.],[0., 0.84147098, 0.90929743]])
對於矩陣計算,目前ndarray已經覆蓋了np.matrix的大部分的常用操作。因此不必刻意學習np.matrix。比如對一個ndarray取T屬性就得到了它的轉置,使用np.dot進行矩陣相乘
k = np.array([[1],[2]]) l = k.T print(k.shape) # (2, 1) print(l.shape) # (1, 2) m = np.dot(k,l) print(m) # [[1, 2],[2, 4]]
4. 切片
numpy的切片操作和python list的切片操作非常類似。有必要的話,可以點選下面的連結複習list的切片。
ofollow,noindex">切片在numpy裡,對一個ndarray的切片仍然是使用中括號操作符,每個維度的切片設定用逗號隔開。如果一個切片被單一數字代替,則切片的同時伴隨著取分量。我們舉兩個例子說明。
n = np.array([[[1,2],[3,4],[5,6]],[[7,8],[9,10],[11,12]]]) print(n.shape) # (2, 3, 2) print(n[:1,1:,0])# [[ 3,5]]
怎樣理解這個過程呢?我們首先理解n[:,:,0]。前兩個維度的切片都是冒號,意思是不進行切片操作。第三個軸切片其實不是切片,而是對第三個維度取分量。這就意味著所有的第三個維度都要進行一次[0]這樣的操作。比如,[1,2]取索引為0的分量就變成了數字1。我們把它打印出來:
print(n[:,:,0]) # [[ 1,3,5],[ 7,9, 11]]
所以這個時候的維度已經降了下來。然後我們再考慮n[:,1:,0]。第二個維度上切片1:的意思是,對第二個維度從索引1開始取到結尾。這確實是一個真正的切片操作。[1,3,5]取1:分量就是[3,5]。我們把它打印出來
print(n[:,1:,0])# [[3,5],[9,11]]
最後我們理解n[:1,1:,0],它在n[:,1:,0]的基礎上,對第一個維度進行切片。它的所有分量都是一個整體,所以就相當於 [n[0]],即[3,5]作為分量保留了下來。
需要指出的是,切片操作可以粗略的認為是某種可以賦值的『左值』。比如說
n[:,1:,:] = 0 print(n) #[[[1, 2],[0, 0],[0, 0]],[[7, 8],[0, 0],[0, 0]]]
等號右邊的值要麼是個簡單數字,要麼是個shape相同的ndarray。這個和數學計算是相同的道理。
在切片的程式碼風格上,強烈建議大家不要寫維度低於原array維度的切片,除非你不知道原ndarray的維度(例如是通過引數傳遞進來的)。上面的例子裡,n[:,1:]是個合法的操作,雖然只聲明瞭兩個維度的操作。numpy有一系列的複雜規則去理解這樣的不完全的切片(例如n[:,1:]會被等價於n[:,1:,:]而不是n[:,:,1:]),但壞處是你的程式碼難以理解和除錯。
寫在最後
本文只作為快速入門之用,不追求面面俱到。比如說,numpy的中括號操作符遠不止取分量、取切片這兩種用法,其他的用法比如索引等,本文限於篇幅沒有涉及。有興趣的讀者宜直接閱讀官方文件。