Python NumPy教程

基礎篇

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

例如,在3D空間一個點的坐標[1, 2, 3]是一個秩為1的數組,因為它只有一個軸。那個軸長度為3.又例如,在以下例子中,數組的秩為2(它有兩個維度).第一個維度長度為2,第二個維度長度為3.

[[ 1., 0., 0.],
 [ 0., 1., 2.]] 

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

栗子:

In [2]: from  numpy  import * 

In [3]: a = arange(15).reshape(3,5)

In [4]: a
Out[4]: 
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])

In [5]: a.shape 
Out[5]: (3, 5)

In [6]: a.ndim
Out[6]: 2

In [7]: a.dtype.name 
Out[7]: 'int64'

In [8]: a.itemsize
Out[8]: 8

In [9]: a.size
Out[9]: 15

In [10]: type(a) 
Out[10]: numpy.ndarray

In [11]: b = array([6,7,8])

In [12]: b
Out[12]: array([6, 7, 8])

In [13]: type(b) 
Out[13]: numpy.ndarray

創建數組

有好幾種創建數組的方法
例如,你可以使用array函數從常規的Python列表個元組創建數組。所創建的數組類型由原序列中的元素類型推導而來。

In [14]: from  numpy import * 

In [15]: a = array([2,3,4])

In [16]: a
Out[16]: array([2, 3, 4])

In [17]: a.dtype
Out[17]: dtype('int64')

In [18]: b = array([1.2,3.5,5.1]) 

In [19]: b.dtype
Out[19]: dtype('float64')

一個常見的錯誤包括用多個數值參數調用array而不是提供一個由數值組成的列表作為一個參數。

In [20]: a = array(1,2,3,4) 
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-20-79e204e243c8> in <module>()
----> 1 a = array(1,2,3,4)

ValueError: only 2 non-keyword arguments accepted

In [21]: a = array([1,2,3,4]) 

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

In [22]: b = array([(1.5,2,3),(4,5,6)]) 

In [23]: b
Out[23]: 
array([[ 1.5,  2. ,  3. ],
       [ 4. ,  5. ,  6. ]])

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

In [24]: c = array([[1,2],[3,4]],dtype=complex)

In [25]: c
Out[25]: 
array([[ 1.+0.j,  2.+0.j],
       [ 3.+0.j,  4.+0.j]])

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

函數function創建一個全是0的數組,函數ones創建一個全1的數組,函數empty創建一個內容隨機并且依賴與內存狀態的數組。默認創建的數組類型(dtype)都是float64。

In [26]: zeros( (3,4) )
Out[26]: 
array([[ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.]])

In [27]: ones( (2,3,4), dtype=int16 ) 
Out[27]: 
array([[[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]],

       [[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]]], dtype=int16)

In [28]: empty( (2,3) )
Out[28]: 
array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])

為了創建一個數列,NumPy提供一個類似arange的函數返回數組而不是列表:

In [29]: arange(10,30,5) 
Out[29]: array([10, 15, 20, 25])

In [30]: arange(0,2,0.3)    # it accepts float arguments
Out[30]: array([ 0. ,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8])

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

打印數組

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

  • 最后的軸從左到右打印
  • 次后的軸從頂向下打印
  • 剩下的軸從頂向下打印,每個切片通過一個空行與下一個隔開

一維數組被打印成行,二維數組成矩陣,三維數組成矩陣列表。

In [31]: a = arange(6) 

In [32]: print(a) 
[0 1 2 3 4 5]

In [33]: b = arange(12).reshape(4,3) 

In [34]: print(b) 
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]

In [35]: c = arange(24).reshape(2,3,4) 

In [36]: print(c) 
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]

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

In [37]: print(arange(10000))
[   0    1    2 ..., 9997 9998 9999]

In [38]: print(arange(10000).reshape(100,100))
[[   0    1    2 ...,   97   98   99]
 [ 100  101  102 ...,  197  198  199]
 [ 200  201  202 ...,  297  298  299]
 ..., 
 [9700 9701 9702 ..., 9797 9798 9799]
 [9800 9801 9802 ..., 9897 9898 9899]
 [9900 9901 9902 ..., 9997 9998 9999]]

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

>>> set_printoptions(threshold='nan') 

基本運算

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

In [1]: from numpy import  * 

In [2]: a = array([20,30,40,50]) 

In [3]: b = arange(4) 

In [4]: b 
Out[4]: array([0, 1, 2, 3])

In [5]: c = a - b 

In [6]: c 
Out[6]: array([20, 29, 38, 47])

In [7]: b**2
Out[7]: array([0, 1, 4, 9])

In [8]: 10*sin(a) 
Out[8]: array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])

In [9]: a<35
Out[9]: array([ True,  True, False, False], dtype=bool)

不像許多矩陣語言,NumPy中的乘法運算符*指示按元素計算,矩陣乘法可以使用dot函數或創建矩陣對象實現

In [10]: A = array([[1,1],[0,1]]) 

In [11]: B = array([[2,0],[3,4]]) 

In [12]: A*B
Out[12]: 
array([[2, 0],
       [0, 4]])

In [13]: dot(A,B) 
Out[13]: 
array([[5, 4],
       [3, 4]])

有些操作符像+=和*=被用來更改已存在數組而不是創建一個新的數組

In [14]: a = ones((2,3),dtype=int)

In [15]: a
Out[15]: 
array([[1, 1, 1],
       [1, 1, 1]])

In [16]: b = random.random((2,3))

In [17]: b
Out[17]: 
array([[ 0.59203579,  0.33035089,  0.77216489],
       [ 0.57561703,  0.73380547,  0.10118917]])

In [18]: a *=3

In [19]: a
Out[19]: 
array([[3, 3, 3],
       [3, 3, 3]])

In [20]: b += a 

In [21]: b
Out[21]: 
array([[ 3.59203579,  3.33035089,  3.77216489],
       [ 3.57561703,  3.73380547,  3.10118917]])

In [22]: a += b 
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-22-368d0b76b60a> in <module>()
----> 1 a += b

TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int64') with casting rule 'same_kind'

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

In [24]: a = ones(3,dtype=int32)

In [25]: b = linspace(0,pi,3)

In [26]: b.dtype.name
Out[26]: 'float64'

In [27]: c = a + b 

In [28]: c 
Out[28]: array([ 1.        ,  2.57079633,  4.14159265])

In [29]: c.dtype.name
Out[29]: 'float64'

In [30]: d = exp(c*1j) 

In [31]: d 
Out[31]: 
array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
       -0.54030231-0.84147098j])

In [32]: d.dtype.name
Out[32]: 'complex128'
'complex128' 許多非數組運算,如計算數組所有元素之和,被作為ndarray類的方法實現

In [33]: a = random.random((2,3))

In [34]: a
Out[34]: 
array([[ 0.47405377,  0.3554812 ,  0.77247355],
       [ 0.28015991,  0.28447145,  0.27666715]])

In [35]: a.sum()
Out[35]: 2.4433070197253133

In [36]: a.min()
Out[36]: 0.27666714728871389

In [37]: a.max()
Out[37]: 0.77247354602573004

這些運算默認應用到數組好像它就是一個數字組成的列表,無關數組的形狀。然而,指定axis參數你可以吧運算應用到數組指定的軸上:

In [38]: b = arange(12).reshape(3,4) 

In [39]: b
Out[39]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [40]: b.sum(axis=0)   # sum of each column
Out[40]: array([12, 15, 18, 21])

In [41]: b.min(axis=1)   # min of each row
Out[41]: array([0, 4, 8])

In [42]: b.cumsum(axis=1)   # cumulative sum along each rowOut[42]: 
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]])

通用函數(ufunc)

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

In [43]: B = arange(3) 

In [44]: B 
Out[44]: array([0, 1, 2])

In [45]: exp(B) 
Out[45]: array([ 1.        ,  2.71828183,  7.3890561 ])

In [46]: sqrt(B) 
Out[46]: array([ 0.        ,  1.        ,  1.41421356])

In [47]: C = array([2.,-1,4.]) 

In [48]: add(B,c) 
Out[48]: array([ 1.        ,  3.57079633,  6.14159265])

更多函數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 參見:<a href=http://scipy.org/Numpy_Example_List>[NumPy示例]</a>

索引,切片和迭代

一維數組可以被索引,切片和迭代,就像列表和其它Python序列。

In [49]: a = arange(10)**3 

In [50]: a 
Out[50]: array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729])

In [51]: a[2] 
Out[51]: 8

In [52]: a[2:5] 
Out[52]: array([ 8, 27, 64])

In [53]: a[:6:2] = -1000 

In [54]: a 
Out[54]: array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,   729])

In [55]: a[::-1]
Out[55]: array([  729,   512,   343,   216,   125, -1000,    27, -1000,     1, -1000])

In [56]: for i in a:
    ...:     print(i**(1/3.),)
    ...:     
/usr/local/bin/ipython:2: RuntimeWarning: invalid value encountered in power
  
nan
1.0
nan
3.0
nan
5.0
6.0
7.0
8.0
9.0

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

In [57]: def f(x,y):
    ...:     return 10*x + y 
    ...: 

In [58]: b = fromfunction(f,(5,4),dtype=int)

In [59]: b
Out[59]: 
array([[ 0,  1,  2,  3],
       [10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33],
       [40, 41, 42, 43]])

In [60]: b[2,3] 
Out[60]: 23

In [61]: b[0:5,1]      # each row in the second column of b
Out[61]: array([ 1, 11, 21, 31, 41])

In [62]: b[ : ,1]     # equivalent to the previous example
Out[62]: array([ 1, 11, 21, 31, 41])

In [63]: b[1:3,:]    # each column in the second and third row of b
Out[63]: 
array([[10, 11, 12, 13],
       [20, 21, 22, 23]])

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

In [64]: b[-1]      # the last row. Equivalent to b[-1,:]
Out[64]: array([40, 41, 42, 43])

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

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

  • x[1,2,…] 等同于 x[1,2,:,:,:],
  • x[…,3] 等同于 x[:,:,:,:,3]
  • x[4,…,5,:] 等同 x[4,:,:,5,:].
 >>> c = array( [ [[ 0, 1, 2], # a 3D array (two stacked 2D arrays) ... [ 10, 12, 13]], ... ... [[100,101,102], ... [110,112,113]] ] ) >>> c.shape (2, 2, 3) >>> c[1,...] # same as c[1,:,:] or c[1] array([[100, 101, 102], [110, 112, 113]]) >>> c[...,2] # same as c[:,:,2] array([[ 2, 13], [102, 113]]) 

迭代多維數組是就第一軸而言的:

In [65]: for row in b:
    ...:     print(row) 
    ...:     
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]

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

In [67]: for element in b.flat:
    ...:     print(element)
    ...:      
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43

更多[], …, newaxis, ndenumerate, indices, index exp 參考<a href=http://scipy.org/Numpy_Example_List a>[NumPy示例] </a>

形狀操作

更改數組
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容