Numpy簡單介紹
1.Numpy是什麼
很簡單,Numpy是Python的一個科學計算的庫,提供了矩陣運算的功能,其一般與Scipy、matplotlib一起使用。其實,list已經提供了類似於矩陣的表示形式,不過numpy為我們提供了更多的函式。如果接觸過matlab、scilab,那麼numpy很好入手。 在以下的程式碼示例中,總是先匯入了numpy:(通用做法import numpu as np 簡單輸入)
>>> import numpy as np >>> print np.version.version 1.6.2
2. 多維陣列
多維陣列的型別是:numpy.ndarray。
使用numpy.array方法
以list或tuple變數為引數產生一維陣列:
>>> print np.array([1,2,3,4]) [1 2 3 4] >>> print np.array((1.2,2,3,4)) [ 1.2 2. 3. 4. ] >>> print type(np.array((1.2,2,3,4))) <type 'numpy.ndarray'>
以list或tuple變數為元素產生二維陣列或者多維陣列:
>>> x = np.array(((1,2,3),(4,5,6))) >>> x array([[1, 2, 3], [4, 5, 6]]) >>> y = np.array([[1,2,3],[4,5,6]]) >>> y array([[1, 2, 3], [4, 5, 6]])
numpy資料型別設定與轉換
numpy ndarray資料型別可以透過引數dtype 設定,而且可以使用astype轉換型別,在處理檔案時候這個會很實用,注意astype 呼叫會返回一個新的陣列,也就是原始資料的一份複製。
numeric_strings2 = np.array(['1.23','2.34','3.45'],dtype=np.string_) numeric_strings2 Out[32]: array(['1.23', '2.34', '3.45'], dtype='|S4') numeric_strings2.astype(float) Out[33]: array([ 1.23, 2.34, 3.45])
numpy索引與切片
index 和slicing :第一數值類似陣列橫座標,第二個為縱座標
>>> x[1,2] 6 >>> y=x[:,1] >>> y array([2, 5])
涉及改變相關問題,我們改變上面y是否會改變x?這是特別需要關注的!
>>> y array([2, 5]) >>> y[0] = 10 >>> y array([10, 5]) >>> x array([[ 1, 10, 3], [ 4, 5, 6]])
透過上面可以發現改變y會改變x ,因而我們可以推斷,y和x指向是同一塊記憶體空間值,系統沒有為y 新開闢空間把x值賦值過去。
arr = np.arange(10) arr Out[45]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) arr[4] Out[46]: 4 arr[3:6] Out[47]: array([3, 4, 5]) arr[3:6] = 12 arr Out[49]: array([ 0, 1, 2, 12, 12, 12, 6, 7, 8, 9])
如上所示:當將一個標量賦值給切片時,該值會自動傳播整個切片區域,這個跟列表最重要本質區別,陣列切片是原始陣列的檢視,檢視上任何修改直接反映到源資料上面。
思考為什麼這麼設計? Numpy 設計是為了處理大資料,如果切片採用資料複製話會產生極大的效能和記憶體消耗問題。
假如說需要對陣列是一份副本而不是檢視可以如下操作:
arr_copy = arr[3:6].copy() arr_copy[:]=24 arr_copy Out[54]: array([24, 24, 24]) arr Out[55]: array([ 0, 1, 2, 12, 12, 12, 6, 7, 8, 9])
再看下對list 切片修改
l=range(10) l Out[35]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] l[5:8] = 12 Traceback (most recent call last): File "<ipython-input-36-022af3ddcc9b>", line 1, in <module> l[5:8] = 12 TypeError: can only assign an iterable l1= l[5:8] l1 Out[38]: [5, 6, 7] l1[0]=12 l1 Out[40]: [12, 6, 7] l Out[41]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
這裡設計到python 中深淺複製,其中切片屬於淺複製
多維陣列索引、切片
arr2d = np.arange(1,10).reshape(3,3) arr2d Out[57]: array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) arr2d[2] Out[58]: array([7, 8, 9]) arr2d[0][2] Out[59]: 3 arr2d[0,2] Out[60]: 3
布林型索引
這種型別在實際程式碼中出現比較多,關注下。
names = np.array(['Bob','joe','Bob','will']) names == 'Bob' Out[70]: array([ True, False, True, False], dtype=bool)
data Out[73]: array([[ 0.36762706, -1.55668952, 0.84316735, -0.116842 ], [ 1.34023966, 1.12766186, 1.12507441, -0.68689309], [ 1.27392366, -0.43399617, -0.80444728, 1.60731881], [ 0.23361565, 1.38772715, 0.69129479, -1.19228023], [ 0.51353082, 0.17696698, -0.06753478, 0.80448168], [ 0.21773096, 0.60582802, -0.46446071, 0.83131122], [ 0.50569072, 0.04431685, -0.69358155, -0.9629124 ]]) data[data < 0] = 0 data Out[75]: array([[ 0.36762706, 0. , 0.84316735, 0. ], [ 1.34023966, 1.12766186, 1.12507441, 0. ], [ 1.27392366, 0. , 0. , 1.60731881], [ 0.23361565, 1.38772715, 0.69129479, 0. ], [ 0.51353082, 0.17696698, 0. , 0.80448168], [ 0.21773096, 0.60582802, 0. , 0.83131122], [ 0.50569072, 0.04431685, 0. , 0. ]])
上面展示透過布林值來設定值的手段。
陣列檔案輸入輸出
在跑實驗時經常需要用到讀取檔案中的資料,其實在numpy中已經有成熟函式封裝好了可以使用
將陣列以二進位制形式格式儲存到磁碟,np.save 、np.load 函式是讀寫磁碟的兩個主要函式,預設情況下,陣列以未壓縮的原始二進位制格式儲存在副檔名為.npy的檔案中
arr = np.arange(10) np.save('some_array',arr) np.load('some_array.npy') Out[80]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
存取文字檔案:
文字中存放是聚類需要資料,直接可以方便讀取到numpy array中,省去一行行讀檔案繁瑣。
arr = np.loadtxt('dataMatrix.txt',delimiter=' ') arr Out[82]: array([[ 1. , 1. , 1. , 1. , 1. , 0.8125 ], [ 0.52882353, 0.56271186, 0.48220588, 0.53384615, 0.61651376, 0.58285714], [ 0. , 0. , 0. , 1. , 1. , 1. ], [ 1. , 0.92857143, 0.91857143, 1. , 1. , 1. ], [ 1. , 1. , 1. , 1. , 1. , 1. ], [ 0.05285714, 0.10304348, 0.068 , 0.06512821, 0.05492308, 0.05244898], [ 0.04803279, 0.08203125, 0.05516667, 0.05517241, 0.04953488, 0.05591549], [ 0.04803279, 0.08203125, 0.05516667, 0.05517241, 0.04953488, 0.05591549]])
np.savetxt 執行相反的操作,這兩個函式在跑實驗載入資料時可以提供很多便利!!!
使用numpy.arange方法
>>> print np.arange(15) [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] >>> print type(np.arange(15)) <type 'numpy.ndarray'> >>> print np.arange(15).reshape(3,5) [[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14]] >>> print type(np.arange(15).reshape(3,5)) <type 'numpy.ndarray'>
使用numpy.linspace方法
例如,在從1到10中產生20個數:
>>> print np.linspace(1,10,20) [ 1. 1.47368421 1.94736842 2.42105263 2.89473684 3.36842105 3.84210526 4.31578947 4.78947368 5.26315789 5.73684211 6.21052632 6.68421053 7.15789474 7.63157895 8.10526316 8.57894737 9.05263158 9.52631579 10. ]
使用numpy.zeros,numpy.ones,numpy.eye等方法可以構造特定的矩陣
>>> print np.zeros((3,4)) [[ 0. 0. 0. 0.] [ 0. 0. 0. 0.] [ 0. 0. 0. 0.]] >>> print np.ones((3,4)) [[ 1. 1. 1. 1.] [ 1. 1. 1. 1.] [ 1. 1. 1. 1.]] >>> print np.eye(3) [[ 1. 0. 0.] [ 0. 1. 0.] [ 0. 0. 1.]]
獲取陣列的屬性
>>> a = np.zeros((2,2,2)) >>> print a.ndim #陣列的維數 3 >>> print a.shape #陣列每一維的大小 (2, 2, 2) >>> print a.size #陣列的元素數 8 >>> print a.dtype #元素型別 float64 >>> print a.itemsize #每個元素所佔的位元組數 8
合併陣列
使用numpy下的vstack(垂直方向)和hstack(水平方向)函式:
>>> a = np.ones((2,2)) >>> b = np.eye(2) >>> print np.vstack((a,b)) [[ 1. 1.] [ 1. 1.] [ 1. 0.] [ 0. 1.]] >>> print np.hstack((a,b)) [[ 1. 1. 1. 0.] [ 1. 1. 0. 1.]]
看一下這兩個函式有沒有涉及到淺複製這種問題:
>>> c = np.hstack((a,b)) >>> print c [[ 1. 1. 1. 0.] [ 1. 1. 0. 1.]] >>> a[1,1] = 5 >>> b[1,1] = 5 >>> print c [[ 1. 1. 1. 0.] [ 1. 1. 0. 1.]]
透過上面可以知道,這裡進行是深複製,而不是引用指向同一位置的淺複製。
深複製陣列
陣列物件自帶了淺複製和深複製的方法,但是一般用深複製多一些:
>>> a = np.ones((2,2)) >>> b = a >>> b is a True >>> c = a.copy() #深複製 >>> c is a False
基本的矩陣運算
轉置:
>>> a = np.array([[1,0],[2,3]]) >>> print a [[1 0] [2 3]] >>> print a.transpose() [[1 2] [0 3]]
numpy.linalg模組中有很多關於矩陣運算的方法:
特徵值、特徵向量:
>>> a = np.array([[1,0],[2,3]]) >>> nplg.eig(a) (array([ 3., 1.]), array([[ 0. , 0.70710678], [ 1. , -0.70710678]]))