Python資料分析之numpy

wengJJ發表於2018-07-23

前言


剛開始學習資料探勘時,有時總是對numpypandas傻傻分不清楚,這個問題在訓練模型階段輸入訓練資料的時候最為明顯,下面就來詳細介紹下numpy 

Numpy

WHAT?


numpy是專門為科學計算設計的一個python擴充套件包,為python提供高效率的多維陣列,也被稱為面向陣列計算(array oriented computing),同時numpy也是github上的一個開源專案:numpy,numpy是基於c語言開發,所以這使得numpy的執行速度很快,高效率執行就是numpy的一大優勢。

首先·我們要匯入numpy包,一般我們都把它命名為np

In [1]: import numpy as np 

接著就可以生成一個numpy一維陣列: 

In [2]: a = np.array([[1,2,3]],dtype=np.int32)
In [3]: a
Out[3]: array([1, 2, 3]) 

numpy中定義的最重要的資料結構是稱為ndarray的n維陣列型別,這個結構引用了兩個物件,一塊用於儲存資料的儲存區域和一個用於描述元素型別的dtype物件: 

Python資料分析之numpy

WHY?


二維陣列的生成在python中我們還可以用到list列表,如果用list來表示[1,2,3],由於list中的元素可以是任何物件,所以list中儲存的是物件的指標,如果要儲存[1,2,3]就需要三個指標和三個整數物件,是比較浪費記憶體資源cpu計算時間的,而ndarray是一種儲存單一資料型別的多維陣列結構,在資料處理上比list列表要快上很多,在這裡我們可以用%timeit命令來檢測兩者的資料處理速度: 

In [9]: a = range(1000)
In [10]: %timeit[i**2 for i in a]
381 µs ± 6.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [11]: b = np.arange(1000)
In [12]: %timeit b**2
1.41 µs ± 18 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 

由於相同資料大小的array運算直接作用到元素級上這一numpy特性,結果顯而易見,在資料處理上numpy陣列比使用for迴圈的list列表快的不是一點兩點。 

HOW?


OK,知道了numpy大概是個什麼東西,下面我們就來介紹下numpy陣列的一些常用操作:

這裡生成一個3×3的矩陣作為例子:

In [2]: data = np.array([[1,2,3],[4,5,6],[7,8,9]]) #等價於data=np.arange(1,10).reshape(3,3)
In [3]: data
Out[3]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]]) 

檢視矩陣資訊: 

In [6]: data.shape    #返回元組,表示n行n列
Out[6]: (3, 3)

In [7]: data.dtype    #返回陣列資料型別
Out[7]: dtype('int32')

In [8]: data.ndim    #返回是幾維陣列
Out[8]: 2 

轉換資料型別:

In [11]: a = data.astype(float)    #拷貝一份新的陣列

In [12]: a.dtype
Out[12]: dtype('float64')

陣列之間的計算:

In [15]: data+data
Out[15]:
array([[ 2,  4,  6],
       [ 8, 10, 12],
       [14, 16, 18]])

In [16]: data*data
Out[16]:
array([[ 1,  4,  9],
       [16, 25, 36],
       [49, 64, 81]])

可以看出相同規格的陣列計算是直接作用在其元素級上的,那不同的規格的陣列是否能進行運算呢,我們來看下這個例子:

In [18]: data1 = np.array([[1,2],[1,2]])    #生成一個2x2numpy陣列

In [19]: data+data1
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-19-f2592a975589> in <module>()
----> 1 data+data1

ValueError: operands could not be broadcast together with shapes (3,3) (2,2)

我們可以看出不同規格的陣列一起計算的話是會報出廣播錯誤的,那是不是可以下結論了,別急我們再來看下方兩個特殊例子:

In [20]: data2 = np.array([[1,2,3]])

In [21]: data + data2
Out[21]:
array([[ 2,  4,  6],
       [ 5,  7,  9],
       [ 8, 10, 12]])

In [22]: data3 = np.array([[1],[2],[3]])

In [23]: data+data3
Out[23]:
array([[ 2,  3,  4],
       [ 6,  7,  8],
       [10, 11, 12]])

data2陣列的列數量與data陣列相等,data3陣列的行數量與data陣列相等,這兩個numpy陣列雖然規格與data陣列不一樣,但卻依然可以與data陣列進行運算。

陣列的切片:

In [24]: data[:2]    #沿著行(axis=0)進行索引
Out[24]:
array([[1, 2, 3],
       [4, 5, 6]])

In [25]: data[:2,:2]    #先沿著行(axis=0)進行索引,再沿著列(axis=1)進行索引
Out[25]:
array([[1, 2],
       [4, 5]])

In [26]: data[1,0:2]    #下標是從0開始
Out[26]: array([4, 5])

這裡需要注意的是,切片操作是在原始陣列上建立一個檢視view,這只是訪問陣列資料的一種方式。 因此原始陣列不會被複制到記憶體中,傳遞的是一個類似引用的東西,與上面的astype()方法是兩種不同的拷貝方式,這裡我們來看一個例子:

In [32]: a = data[1]

In [33]: a
Out[33]: array([4, 5, 6])

In [34]: a[:] = 0

In [35]: data
Out[35]:
array([[1, 2, 3],
       [0, 0, 0],
       [7, 8, 9]])

當切片物件a改變時,data的對應值也會跟著改變,這是在我們日常資料處理中有時會疏忽的一個點,最安全的複製方法是使用

copy()方法進行淺拷貝:

In [36]: a = data[1].copy()

In [37]: a
Out[37]: array([0, 0, 0])

In [38]: a[:]=9

In [39]: data
Out[39]:
array([[1, 2, 3],
       [0, 0, 0],
       [7, 8, 9]])

陣列的布林索引:

In [43]: data
Out[43]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [44]: data>3
Out[44]:
array([[False, False, False],
       [ True,  True,  True],
       [ True,  True,  True]])

In [45]: data[data>3]    #找出大於3的元素
Out[45]: array([4, 5, 6, 7, 8, 9])

陣列的邏輯表達處理:

In [46]: np.where(data>3,1,0)    #大於3的標記為1,小於等於3的標記為0
Out[46]:
array([[0, 0, 0],
       [1, 1, 1],
       [1, 1, 1]])

陣列的常用統計操作:

In [47]: data.mean(axis=0)    #沿著行(axis=0)進行索引,求出其平均值
Out[47]: array([4., 5., 6.])
In [49]: data.std()    #求出全部元素的方差
Out[49]: 2.581988897471611

In [50]: (data>3).sum()    #統計陣列中元素大於3的個數
Out[50]: 6

In [51]: data.any()    #陣列中是否存在一個或多個true
Out[51]: True

In [52]: data.all()    #陣列中是否全部數都是true
Out[52]: True
In [53]: data.cumsum(0)    #沿著行(axis=0)進行索引,進行累加
Out[53]:
array([[ 1,  2,  3],
       [ 5,  7,  9],
       [12, 15, 18]], dtype=int32)

In [54]: data.cumprod(1)    #沿著列(axis=1)進行索引,進行累乘
Out[54]:
array([[  1,   2,   6],
       [  4,  20, 120],
       [  7,  56, 504]], dtype=int32)

陣列的排序操作:

In [55]: data=np.random.randn(4,4)

In [56]: data
Out[56]:
array([[ 1.58669867,  1.57692769, -1.85828013,  1.17201164],
       [ 1.68160714, -0.83957549, -0.33771694, -0.33782379],
       [-0.03148106, -0.97819034,  0.51126626, -0.08184963],
       [-0.02822319, -0.31934723,  0.70764701,  0.80444954]])

In [57]: data.sort(0)    #沿著行(axis=0)進行索引,並進行升序排序

In [58]: data
Out[58]:
array([[-0.03148106, -0.97819034, -1.85828013, -0.33782379],
       [-0.02822319, -0.83957549, -0.33771694, -0.08184963],
       [ 1.58669867, -0.31934723,  0.51126626,  0.80444954],
       [ 1.68160714,  1.57692769,  0.70764701,  1.17201164]])

In [59]: data[::-1]    #降序操作
Out[59]:
array([[ 1.68160714,  1.57692769,  0.70764701,  1.17201164],
       [ 1.58669867, -0.31934723,  0.51126626,  0.80444954],
       [-0.02822319, -0.83957549, -0.33771694, -0.08184963],
       [-0.03148106, -0.97819034, -1.85828013, -0.33782379]])

注意:直接呼叫陣列的方法的排序將直接改變陣列而不會產生新的拷貝。

矩陣運算:

In [62]: x=np.arange(9).reshape(3,3)

In [63]: x
Out[63]:
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [64]: np.dot(x,x)    #矩陣相乘
Out[64]:
array([[ 15,  18,  21],
       [ 42,  54,  66],
       [ 69,  90, 111]])

In [65]: x.T    #矩陣轉置
Out[65]:
array([[0, 3, 6],
       [1, 4, 7],
       [2, 5, 8]])

在numpy中的linalg中有還有很多矩陣運算,比如svd分解,qr分解,cholesky分解等等。

numpy資料的讀取和儲存:

In [68]: np.save('name',data)

In [69]: np.load('name.npy')
Out[69]:
array([[-0.03148106, -0.97819034, -1.85828013, -0.33782379],
       [-0.02822319, -0.83957549, -0.33771694, -0.08184963],
       [ 1.58669867, -0.31934723,  0.51126626,  0.80444954],
       [ 1.68160714,  1.57692769,  0.70764701,  1.17201164]])

總結


numpy的知識學到這裡,就已經可以應付好日常的資料處理了,便捷的操作,高效的處理,都使得numpy成為科學計算的一大利器。

才學疏淺,歡迎評論指導 

參考資料:

易百教程-numpy教程

scipy講義-numpy

LEVEL-numpy ndarray詳解

相關文章