Python NumPy學習
NumPy是Python語言的一個擴充程式庫。支援高階大量的維度陣列與矩陣運算,此外也針對陣列運算提供大量的數學函式庫。Numpy內部解除了Python的GIL(全域性直譯器鎖),執行效率極好,是大量機器學習框架的基礎庫! 關於GIL請參考部落格:http://www.cnblogs.com/wj-1314/p/9056555.html NumPy的全名為Numeric Python,是一個開源的Python科學計算庫,它包括: 一個強大的N維陣列物件ndrray; 比較成熟的(廣播)函式庫; 用於整合C/C++和Fortran程式碼的工具包; 實用的線性代數、傅立葉變換和隨機數生成函式 1.1 NumPy的優點: 對於同樣的數值計算任務,使用NumPy要比直接編寫Python程式碼便捷得多; NumPy中的陣列的儲存效率和輸入輸出效能均遠遠優於Python中等價的基本資料結構,且其能夠提升的效能是與陣列中的元素成比例的; NumPy的大部分程式碼都是用C語言寫的,其底層演算法在設計時就有著優異的效能,這使得NumPy比純Python程式碼高效得多 當然,NumPy也有其不足之處,由於NumPy使用記憶體對映檔案以達到最優的資料讀寫效能,而記憶體的大小限制了其對TB級大檔案的處理;此外,NumPy陣列的通用性不及Python提供的list容器。因此,在科學計算之外的領域,NumPy的優勢也就不那麼明顯。 二、陣列ndarray NumPy最重要的一個特點就是其N維陣列物件(即ndarray),該物件是一個快速而靈活的大資料集容器,該物件由兩部分組成: 實際的資料; 描述這些資料的元資料; Numpy中定義的最重要的物件是成為ndarray的N維陣列型別。它描述相同型別的元素集合。可以使用基於零的索引訪問集合中的專案。 ndarray中的每個元素在記憶體中使用相同大小的塊。ndarray中每個元素是資料型別物件的物件(稱為dtype) 大部分的陣列操作僅僅是修改元資料部分,而不改變其底層的實際資料。陣列的維數稱為秩,簡單來說就是如果你需要獲取陣列中一個特定元素所需的座標數,如a是一個2×3×4的矩陣,你索引其中的一個元素必須給定三個座標a[x,y,z],故它的維數就是3。而軸可以理解為一種對陣列空間的分割,以陣列a為例,如果我們以0為軸,那麼a可以看成是一個由兩個元素構成的陣列,其中每個元素都是一個3×4的陣列。 我們可以直接將陣列看作一種新的資料型別,就像list、tuple、dict一樣,但陣列中所有元素的型別必須是一致的,Python支援的資料型別有整型、浮點型以及複數型,但這些型別不足以滿足科學計算的需求,因此NumPy中添加了許多其他的資料型別,如bool、inti、int64、float32、complex64等。同時,它也有許多其特有的屬性和方法。 官方解釋: + View Code 2.1 常用ndarray屬性: dtype 描述陣列元素的型別 shape 以tuple表示的陣列形狀 ndim 陣列的維度 size 陣列中元素的個數 itemsize 陣列中的元素在記憶體所佔位元組數 T 陣列的轉置 flat 返回一個數組的迭代器,對flat賦值將導致整個陣列的元素被覆蓋 real/imag 給出複數陣列的實部/虛部 import numpy as np # 建立簡單的列表 a = [1,2,3,4,5,6] # 講列表轉換為陣列 b = np.array(a) # Numpy檢視陣列屬性 print(b.size) #6 # 陣列形狀 print(b.shape) # (6,) # 陣列維度 print(b.ndim) # 1 # 陣列元素型別 print(b.dtype) # int32 import numpy as np a = np.array([1,2,3]) print(a) # [1 2 3] # 多於一個維度 a = np.array([[1, 2], [3, 4]]) print(a) # [[1 2] # [3 4]] # 最小維度 a = np.array([1, 2, 3,4,5], ndmin = 2) print(a) # [[1 2 3 4 5]] # dtype 引數 a = np.array([1, 2, 3], dtype = complex) print(a) # [1.+0.j 2.+0.j 3.+0.j] ndarray 物件由計算機記憶體中的一維連續區域組成,帶有將每個元素對映到記憶體塊中某個位置的索引方案。 記憶體塊以按行(C 風格)或按列(FORTRAN 或 MatLab 風格)的方式儲存元素。 2.2 常用ndarray方法: reshape(…) 返回一個給定shape的陣列的副本 resize(…) 返回給定shape的陣列,原陣列shape發生改變 flatten()/ravel() 返回展平陣列,原陣列不改變 astype(dtype) 返回指定元素型別的陣列副本 fill() 將陣列元素全部設定為一個標量值 sum/Prod() 計算所有陣列元素的和/積 mean()/var()/std() 返回陣列元素的均值/方差/標準差 max()/min()/ptp()/median() 返回陣列元素的最大值/最小值/取值範圍/中位數 argmax()/argmin() 返回最大值/最小值的索引 sort() 對陣列進行排序,axis指定排序的軸;kind指定排序演算法,預設是快速排序 view()/copy() view創造一個新的陣列物件指向同一資料;copy是深複製 tolist() 將陣列完全轉為列表,注意與直接使用list(array)的區別 compress() 返回滿足條件的元素構成的陣列 numpy.reshape: import numpy as np a = np.arange(8) print('原始陣列:') print(a) print('\n') b = a.reshape(4,2) print('修改後的陣列:') print(b) '''結果 原始陣列: [0 1 2 3 4 5 6 7] 修改後的陣列: [[0 1] [2 3] [4 5] [6 7]] ''' numpy.ndarray.flatten: import numpy as np a = np.arange(8).reshape(2,4) print('原陣列:') print(a) print('\n') # default is column-major print('展開的陣列:') print(a.flatten()) print('\n') print('以 F 風格順序展開的陣列:') print(a.flatten(order = 'F')) '''結果: 原陣列: [[0 1 2 3] [4 5 6 7]] 展開的陣列: [0 1 2 3 4 5 6 7] 以 F 風格順序展開的陣列: [0 4 1 5 2 6 3 7] ''' numpy.ravel: import numpy as np a = np.arange(8).reshape(2,4) print('原陣列:') print(a) print('\n') print('呼叫 ravel 函式之後:') print(a.ravel()) print('\n') print('以 F 風格順序呼叫 ravel 函式之後:') print(a.ravel(order = 'F')) '''結果: 原陣列: [[0 1 2 3] [4 5 6 7]] 呼叫 ravel 函式之後: [0 1 2 3 4 5 6 7] 以 F 風格順序呼叫 ravel 函式之後: [0 4 1 5 2 6 3 7]''' 2.3 陣列的建立 numpy中使用array()函式建立陣列,array的首個引數一定是一個序列,可以是元組也可以是列表。 2.3.1 一維陣列的建立 可以使用numpy中的arange()函式建立一維有序陣列,它是內建函式range的擴充套件版。 In [1]: import numpy as np In [2]: ls1 = range(www.dfgjpt.com/ 10) In [3]: list(ls1) Out[3]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] In [4]: type(ls1) Out[4]: range In [5]: ls2 = np.arange(10) In [6]: list(ls2) Out[6]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] In [7]: type(ls2) Out[7]: numpy.ndarray 通過arange生成的序列就不是簡簡單單的列表型別了,而是一個一維陣列。 如果一維陣列不是一個規律的有序元素,而是人為的輸入,就需要array()函式建立了。 In [8]: arr1 = np.array((1,20,13,28,22)) In [9]: arr1 Out[9]: array([ 1, 20, 13, 28, 22]) In [10]: type(arr1) Out[10]: numpy.ndarray 上面是由元組序列構成的一維陣列。 In [11]: arr2 = np.array([1,1,2,3,5,8,13,21]) In [12]: arr2 Out[12]: array([ 1, 1, 2, 3, 5, 8, 13, 21]) In [13]: type(arr2) Out[13]: numpy.ndarray 上面是由列表序列構成的一維陣列。 2.3.2 二維陣列的建立 二維陣列的建立,其實在就是列表套列表或元組套元組。 In [14]: arr3 = np.array(((1,1,2,3),(5,8,13,21),(34,55,89,144))) In [15]: arr3 Out[15]: array([[ 1, 1, 2, 3], [ 5, 8, 13, 21], [ 34, 55, 89, 144]]) 上面使用元組套元組的方式。 In [16]: arr4 = np.array(www.yongshiyule178.com [[1,2,3,4],[5,6,7,8],[9,10,11,12]]) In [17]: arr4 Out[17]: array([[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]]) 上面使用列表套列表的方式。 對於高維陣列在將來的資料分析中用的比較少,這裡關於高維陣列的建立就不贅述了,構建方法仍然是套的方式。 上面所介紹的都是人為設定的一維、二維或高維陣列,numpy中也提供了幾種特殊的陣列,它們是: In [18]: np.ones(3) #返回一維元素全為1的陣列 Out[18]: array([ 1., 1., 1.]) In [19]: np.ones([3,4]) #返回元素全為1的3×4二維陣列 Out[19]: array([[ 1., 1., 1., 1.], [ 1., 1., 1., 1.], [ 1., 1., 1., 1.]]) In [20]: np.zeros(3) #返回一維元素全為0的陣列 Out[20]: array([ 0., 0., 0.]) In [21]: np.zeros([3,4]) #返回元素全為0的3×4二維陣列 Out[21]: array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 0., 0., 0., 0.]]) In [22]: np.empty(3) #返回一維空陣列 Out[22]: array(www.00534.cn[ 0., 0., 0.]) In [23]: np.empty([3,4]) #返回3×4二維空陣列 Out[23]: array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 0., 0., 0., 0.]]) 2.3.3 ones函式 返回特定大小,以1填充的新陣列 >>> import numpy as np >>> a=np.ones(3);a array([ 1., 1., 1.]) >>> b=np.ones(www.06640.cn(3,2));b array([[ 1., 1.], [ 1., 1.], [ 1., 1.]]) 2.3.4 zeros函式 返回特定大小,以0填充的新陣列。 官方庫的解釋: def zeros(shape, dtype=None, order='C'): # real signature unknown; restored from __doc__ """ zeros(shape, dtype=float, order='C') Return a new array of given shape and type, filled with zeros. Parameters ---------- shape : int or tuple of ints Shape of the new www.tianzunyule178.com array, e.g., ``(2, 3)`` or ``2``. dtype : data-type, optional The desired data-type for the array, e.g., `numpy.int8`. Default is `numpy.float64`. order : {'C', 'F'}, optional, default: 'C' Whether to store multi-dimensional data in row-major (C-style) or column-major (Fortran-style) order in memory. Returns ------- out : ndarray Array of zeros with the given shape, dtype, and order. See Also -------- zeros_like : Return an array of zeros with shape and type of input. empty : Return a new uninitialized array. ones : Return a new array setting values to one. full : Return a new array of given shape filled with value. Examples -------- >>> np.zeros(5) array([ 0., 0., 0., 0., 0.]) >>> np.zeros((5,), dtype=int) array([0, 0, 0, 0, 0]) >>> np.zeros((2, 1)) array([[ 0.], [ 0.]]) >>> s = (2,2) >>> np.zeros(s) array([[ 0., 0.], [ 0., 0.]]) >>> np.zeros((2,), dtype=[('x', 'i4'), ('y', 'i4')]) # custom dtype array([(0, 0), (0, 0)], dtype=[('x', '<i4'), ('y', '<i4')]) """ pass numpy.zeros(shape, dtype=float, order=’C’) 引數: shape:int或ints序列 新陣列的形狀,例如(2,3 )或2。 dtype:資料型別,可選 陣列的所需資料型別,例如numpy.int8。預設值為 numpy.float64。 order:{'C','F'},可選 是否在儲存器中以C或Fortran連續(按行或列方式)儲存多維資料。 返回: 1 2 out:ndarray 具有給定形狀,資料型別和順序的零陣列。 >>> c=np.zeros(3) >>> c array([ 0., 0., 0.]) >>> d=np.zeros((2,3));d array([[ 0., 0., 0.], [ 0., 0., 0.]]) #d=np.zeros(2,3)會報錯,d=np.zeros(3,dtype=int)來改變預設的資料型別 2.3.5 eye&identity函式 >>> e=np.eye(3);e array([[ 1., 0., 0.], [ 0., 1., 0.], [ 0., 0., 1.]]) >>> e=np.eye(3,2);e array([[ 1., 0.], [ 0., 1.], [ 0., 0.]]) >>> e=np.eye(3,1);e array([[ 1.], [ 0.], [ 0.]]) >>> e=np.eye(3,3);e array([[ 1., 0., 0.], [ 0., 1., 0.], [ 0., 0., 1.]]) >>> e=np.eye(3,3,1);e array([[ 0., 1., 0.], [ 0., 0., 1.], [ 0., 0., 0.]]) e=np.eye(3,3,2);e array([[ 0., 0., 1.], [ 0., 0., 0.], [ 0., 0., 0.]]) >>> e=np.eye(3,3,3);e array([[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]]) >>> e=np.eye(3,3,4);e array([[ 0., 0., 0.], [ 0., 0., 0.], [ 0., 0., 0.]]) >>> p=np.identity(4);p array([[ 1., 0., 0., 0.], [ 0., 1., 0., 0.], [ 0., 0., 1., 0.], [ 0., 0., 0., 1.]]) >>> p=np.identity(4,3);p #會報錯 >>> p=np.identity((4,3));p #會報錯 2.3.6 empty函式 它建立指定形狀和dtype的未初始化陣列。它使用以下建構函式: 1 numpy.empty(shape, dtype = float, order = 'C') 注意:陣列為隨機值,因為他們未初始化。 import numpy as np x = np.empty([3,2], dtype = int) print(x) # [[1762 0] # [ 0 0] # [ 0 0]] >>> a=np.empty(3);a array([ 1.60091154e-163, 1.12069303e-258, 3.23790862e-318]) >>> a=np.empty((3,3));a array([[ 1.57741456e-284, 1.57680914e-284, 1.56735002e-163], [ 1.56205068e-163, 1.62511438e-163, 1.21880041e+171], [ 1.57757869e-052, 7.34292780e+223, 4.71235856e+257]]) 2.3.7 ones_like zero_like empy_like函式 >>> a=np.array([[[1,2],[1,2]],[[1,2],[1,2]],[[1,2],[1,2]]]) >>> a.shape (3, 2, 2) >>> b=np.ones_like(a) >>> b array([[[1, 1], [1, 1]], [[1, 1], [1, 1]], [[1, 1], [1, 1]]]) >>> b=np.zeros_like(a);b array([[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]]) >>> a=np.array([[[1,2],[1,2]],[[1,2],[1,2]],[[1,2],[1,2]]]) >>> b=np.empty_like(a);b array([[[39125057, 40012256], [81313824, 81313856]], [[ 0, 0], [ 0, 0]], [[ 0, 0], [ 0, 0]]]) #注意,shape和dtype均複製 三,Numpy資料型別 NumPy 支援比 Python 更多種類的數值型別。 下表顯示了 NumPy 中定義的不同標量資料型別。 序號 資料型別及描述 1. bool_儲存為一個位元組的布林值(真或假) 2. int_預設整數,相當於 C 的long,通常為int32或int64 3. intc相當於 C 的int,通常為int32或int64 4. intp用於索引的整數,相當於 C 的size_t,通常為int32或int64 5. int8位元組(-128 ~ 127) 6. int1616 位整數(-32768 ~ 32767) 7. int3232 位整數(-2147483648 ~ 2147483647) 8. int6464 位整數(-9223372036854775808 ~ 9223372036854775807) 9. uint88 位無符號整數(0 ~ 255) 10. uint1616 位無符號整數(0 ~ 65535) 11. uint3232 位無符號整數(0 ~ 4294967295) 12. uint6464 位無符號整數(0 ~ 18446744073709551615) 13. float_float64的簡寫 14. float16半精度浮點:符號位,5 位指數,10 位尾數 15. float32單精度浮點:符號位,8 位指數,23 位尾數 16. float64雙精度浮點:符號位,11 位指數,52 位尾數 17. complex_complex128的簡寫 18. complex64複數,由兩個 32 位浮點表示(實部和虛部) 19. complex128複數,由兩個 64 位浮點表示(實部和虛部) NumPy 數字型別是dtype(資料型別)物件的例項,每個物件具有唯一的特徵。 這些型別可以是np.bool_,np.float32等。 3.1 資料型別物件(dtype) 資料型別物件描述了對應於陣列的固定記憶體塊的解釋,取決於以下方面: 資料型別(整數、浮點或者 Python 物件) 資料大小 位元組序(小端或大端) 在結構化型別的情況下,欄位的名稱,每個欄位的資料型別,和每個欄位佔用的記憶體塊部分。 如果資料型別是子序列,它的形狀和資料型別。 位元組順序取決於資料型別的字首<或>。<意味著編碼是小端(最小有效位元組儲存在最小地址中)。>意味著編碼是大端(最大有效位元組儲存在最小地址中)。 dtype語法構造: 1 numpy.dtype(object, align, copy) 引數為: Object:被轉換為資料型別的物件。 Align:如果為true,則向欄位新增間隔,使其類似 C 的結構體。 Copy: 生成dtype物件的新副本,如果為flase,結果是內建資料型別物件的引用。 示例: # 使用陣列標量型別 import numpy as np dt = np.dtype(np.int32) print(dt) # int32 # int8,int16,int32,int64 可替換為等價的字串 'i1','i2','i4',以及其他。 dt = np.dtype('i4') print(dt) # int32 # 使用端記號 dt = np.dtype('>i4') print(dt) # >i4 # 首先建立結構化資料型別。 dt = np.dtype([('age',np.int8)]) print(dt) # [('age', 'i1')] # 現在將其應用於 ndarray 物件 dt = np.dtype([('age',np.int8)]) a = np.array([(10,),(20,),(30,)], dtype = dt) print(a) # [(10,) (20,) (30,)] # 檔名稱可用於訪問 age 列的內容 dt = np.dtype([('age',np.int8)]) a = np.array([(10,),(20,),(30,)], dtype = dt) print(a['age']) # [10 20 30] 四,Numpy 切片和索引 ndarray物件的內容可以通過索引或切片來訪問和修改,就像python的內建容器物件一樣。 nadarray 物件中的元素遵循基於零的索引,有三種可用的索引方法型別:欄位訪問,基礎切片和高階索引。 基本切片是Python中基本切片概念到n維的擴充套件,通過start,stop和step引數提供給內建函式的slice函式來構造一個Python slice物件,此slice物件被傳遞給陣列來提取陣列的一部分。 練習: import numpy as np a = np.arange(10) print(a) # [0 1 2 3 4 5 6 7 8 9] s = slice(2,7,2) print(s) # slice(2, 7, 2) print(a[s]) # [2 4 6] b = a[2:7:2] print(b) # [2 4 6] # 對單個元素進行切片 b = a[5] print(b) # 5 # 對始於索引的元素進行切片 print(a[2:]) # [2 3 4 5 6 7 8 9] # 對索引之間的元素進行切片 print(a[2:5]) # [2 3 4] # 二維陣列 # 最開始的陣列 import numpy as np a = np.array([[1,2,3],[3,4,5],[4,5,6]]) print('我們的陣列是:') print(a) print ('\n') # 這會返回第二列元素的陣列: print ('第二列的元素是:') print(a[...,1]) print('\n') # 現在我們從第二行切片所有元素: print ('第二行的元素是:') print(a[1,...]) print( '\n') # 現在我們從第二列向後切片所有元素: print ('第二列及其剩餘元素是:') print(a[...,1:]) ''' 我們的陣列是: [[1 2 3] [3 4 5] [4 5 6]] 第二列的元素是: [2 4 5] 第二行的元素是: [3 4 5] 第二列及其剩餘元素是: [[2 3] [4 5] [5 6]]''' 五,Numpy-IO ndarray物件可以儲存到磁碟檔案並從磁碟檔案載入,可用的IO功能有: load()和save() 函式處理Numpy 二進位制檔案(帶npy副檔名)。 loadtxt() 和savetxt() 函式處理正常的文字檔案。 Numpy為ndarray物件引入了一個簡單的檔案格式,這個npy檔案在磁碟檔案中,儲存重建ndarray所需的資料,圖形,dtype和其他資訊,以便正確獲取陣列,即使該檔案在具有不同架構的一臺機器上。 numpy.save() 此函式是講檔案輸入陣列儲存在具有npy副檔名的磁碟檔案中。 1 2 3 import numpy as np a = np.array([1,2,3,4,5]) np.save('outfile',a) 為了從outfile.npy重建陣列,請使用load()函式。 1 2 3 4 import numpy as np b = np.load('outfile.npy') print(b) # [1 2 3 4 5] save()和load()函式接受一個附加的布林引數allow_pickles。Python中的pickle用在儲存到磁碟檔案或者從磁碟檔案讀取之前,對物件進行序列化和反序列化。 savetxt() 以簡單文字檔案格式儲存和獲取陣列資料,通過savetxt()和loadtxt()函式來完成的。 import numpy as np a = np.array([1,2,3,4,5]) np.savetxt('out.txt',a) b = np.loadtxt('out.txt') print(b) # [1. 2. 3. 4. 5.] savetxt()和loadtxt()函式接受附加的可選引數,例如頁首,頁尾和分隔符。 六,numpy中的ndarray與array的區別、不同 答:Well, np.array is just a convenience function to create an ndarray, it is not a class itself. (嗯,np.array只是一個便捷的函式,用來建立一個ndarray,它本身不是一個類) You can also create an array using np.ndarray, but it is not the recommended way. From the docstring of np.ndarray: (你也能夠用np.ndarray來建立,但這不是推薦的方式。來自np.ndarray的文件:)