numpy 基礎入門 - 30分鐘學會numpy

pythontab發表於2018-04-03

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]]))


相關文章