Python:一篇文章掌握Numpy的基本用法

dicksonjyl560101發表於2018-01-08

Python:一篇文章掌握Numpy的基本用法

 

https://mp.weixin.qq.com/s?__biz=MzI2NjY5NzI0NA==&mid=2247483867&idx=1&sn=6cafddd7868d4bfd6d2fbc2426cdae9a&chksm=ea8b6ea8ddfce7be7fe108fcc18ad945742f64657007a85805fe8b9ffcb660ae5ab3e3b2f147&scene=21#wechat_redirect

 

前言

Numpy是一個開源的Python科學計算庫,它是python科學計算庫的基礎庫,許多其他著名的科學計算庫如PandasScikit-learn等都要用到Numpy庫的一些功能。

本文主要內容如下:

  1. Numpy陣列物件
  2. 建立ndarray陣列
  3. Numpy的數值型別
  4. ndarray陣列的屬性
  5. ndarray陣列的切片和索引
  6. 處理陣列形狀
  7. 陣列的型別轉換
  8. numpy常用統計函式
  9. 陣列的廣播

1 Numpy陣列物件

Numpy中的多維陣列稱為ndarray,這是Numpy中最常見的陣列物件。ndarray物件通常包含兩個部分:

  • ndarray資料本身
  • 描述資料的後設資料

Numpy陣列的優勢

  • Numpy陣列通常是由相同種類的元素組成的,即陣列中的資料項的型別一致。這樣有一個好處,由於知道陣列元素的型別相同,所以能快速確定儲存資料所需空間的大小。
  • Numpy陣列能夠運用向量化運算來處理整個陣列,速度較快;而Python的列表則通常需要藉助迴圈語句遍歷列表,執行效率相對來說要差。
  • Numpy使用了最佳化過的C API,運算速度較快

關於向量化和標量化運算,對比下面的參考例子就可以看出差異

  • 使用pythonlist進行迴圈遍歷運算

1.         def pySum():

2.             a = list(range(10000))

3.             b = list(range(10000))

4.             c = []

5.             for i in range(len(a)):

6.                 c.append(a[i]**2 + b[i]**2)

7.          

8.             return c

1.         %timeit pySum()

1.         10 loops, best of 3: 49.4 ms per loop

  • 使用numpy進行向量化運算

1.         import numpy as np

2.         def npSum():

3.             a = np.arange(10000)

4.             b = np.arange(10000)

5.             c = a**2 + b**2

6.             return c

1.         %timeit npSum()

1.         The slowest run took 262.56 times longer than the fastest. This could mean that an intermediate result is being cached.

2.         1000 loops, best of 3: 128 ?s per loop

從上面的執行結果可以看出,numpy的向量化運算的效率要遠遠高於python的迴圈遍歷運算(效率相差好幾百倍)。 (1ms=1000?s

2 建立ndarray陣列

首先需要匯入numpy庫,在匯入numpy庫時通常使用“np”作為簡寫,這也是Numpy官方倡導的寫法。

當然,你也可以選擇其他簡寫的方式或者直接寫numpy,但還是建議用“np”,這樣你的程式能和大都數人的程式保持一致。

1.         import numpy as np

建立ndarray陣列的方式有很多種,這裡介紹我使用的較多的幾種:

Method 1: 基於listtuple

1.         # 一維陣列

2.          

3.         # 基於list

4.         arr1 = np.array([1,2,3,4])

5.         print(arr1)

6.          

7.         # 基於tuple

8.         arr_tuple = np.array((1,2,3,4))

9.         print(arr_tuple)

10.       

11.      # 二維陣列 (2*3)

12.      arr2 = np.array([[1,2,4], [3,4,5]])

13.      arr2

1.         [1 2 3 4]

2.         [1 2 3 4]

3.         array([[1, 2, 4],

4.                [3, 4, 5]])

請注意:

  • 一維陣列用print輸出的時候為 [1 2 3 4],跟python的列表是有些差異的,沒有,
  • 在建立二維陣列時,在每個子list外面還有一個"[]",形式為[[list1], [list2]]

Method 2: 基於np.arange

1.         # 一維陣列

2.         arr1 = np.arange(5)

3.         print(arr1)

4.          

5.         # 二維陣列

6.         arr2 = np.array([np.arange(3), np.arange(3)])

7.         arr2

1.         [0 1 2 3 4]

2.         array([[0, 1, 2],

3.                [0, 1, 2]])

Method 3: 基於arange以及reshape建立多維陣列

1.         # 建立三維陣列

2.         arr = np.arange(24).reshape(2,3,4)

3.         arr

1.         array([[[ 0,  1,  2,  3],

2.                 [ 4,  5,  6,  7],

3.                 [ 8,  9, 10, 11]],

4.          

5.                [[12, 13, 14, 15],

6.                 [16, 17, 18, 19],

7.                 [20, 21, 22, 23]]])

  • 請注意:arange的長度與ndarray的維度的乘積要相等,即 24 = 2X3X4
  • numpy.random建立陣列的方法,可以參考下面的文章

為什麼你用不好Numpy的random函式?

  • 其他建立ndarray的方法,各位小夥伴們自己可以研究下。

3 Numpy的數值型別

Numpy的數值型別如下:


每一種資料型別都有相應的資料轉換函式,參考示例如下:

1.         np.int8(12.334)

1.         12

1.         np.float64(12)

1.         12.0

1.         np.float(True)

1.         1.0

1.         bool(1)

1.         True

在建立ndarray陣列時,可以指定數值型別:

1.         a = np.arange(5, dtype=float)

2.         a

1.         array([ 0.,  1.,  2.,  3.,  4.])

  • 請注意,複數不能轉換成為整數型別或者浮點數,比如下面的程式碼會執行出錯


1.         # float(42 + 1j)

4 ndarray陣列的屬性

  • dtype屬性ndarray陣列的資料型別,資料型別的種類,前面已描述。

1.         np.arange(4, dtype=float)

1.         array([ 0.,  1.,  2.,  3.])

1.         # 'D'表示複數型別

2.         np.arange(4, dtype='D')

1.         array([ 0.+0.j,  1.+0.j,  2.+0.j,  3.+0.j])

1.         np.array([1.22,3.45,6.779], dtype='int8')

1.         array([1, 3, 6], dtype=int8)

  • ndim屬性,陣列維度的數量

1.         a = np.array([[1,2,3], [7,8,9]])

2.         a.ndim

1.         2

  • shape屬性,陣列物件的尺度,對於矩陣,即nm,shape是一個元組(tuple

1.         a.shape

1.         (2, 3)

  • size屬性用來儲存元素的數量,相當於shapenXm的值

1.         a.size

1.         6

  • itemsize屬性返回陣列中各個元素所佔用的位元組數大小。

1.         a.itemsize

1.         4

  • nbytes屬性,如果想知道整個陣列所需的位元組數量,可以使用nbytes屬性。其值等於陣列的size屬性值乘以itemsize屬性值。

1.         a.nbytes

1.         24

1.         a.size*a.itemsize

1.         24

  • T屬性,陣列轉置

1.         b = np.arange(24).reshape(4,6)

2.         b

1.         array([[ 0,  1,  2,  3,  4,  5],

2.                [ 6,  7,  8,  9, 10, 11],

3.                [12, 13, 14, 15, 16, 17],

4.                [18, 19, 20, 21, 22, 23]])

1.         b.T

1.         array([[ 0,  6, 12, 18],

2.                [ 1,  7, 13, 19],

3.                [ 2,  8, 14, 20],

4.                [ 3,  9, 15, 21],

5.                [ 4, 10, 16, 22],

6.                [ 5, 11, 17, 23]])

  • 複數的實部和虛部屬性,realimag屬性

1.         d = np.array([1.2+2j, 2+3j])

2.         d

1.         array([ 1.2+2.j,  2.0+3.j])

real屬性返回陣列的實部

1.         d.real

1.         array([ 1.2,  2. ])

imag屬性返回陣列的虛部

1.         d.imag

1.         array([ 2.,  3.])

  • flat屬性,返回一個numpy.flatiter物件,即可迭代的物件。

1.         e = np.arange(6).reshape(2,3)

2.         e

1.         array([[0, 1, 2],

2.                [3, 4, 5]])

1.         f = e.flat

2.         f

1.         <numpy.flatiter at 0x65eaca0>

1.         for item in f:

2.             print(item)

1.         0

2.         1

3.         2

4.         3

5.         4

6.         5

可透過位置進行索引,如下:

1.         f[2]

1.         2

1.         f[[1,4]]

1.         array([1, 4])

也可以進行賦值

1.         e.flat=7

2.         e

1.         array([[7, 7, 7],

2.                [7, 7, 7]])

1.         e.flat[[1,4]]=1

2.         e

1.         array([[7, 1, 7],

2.                [7, 1, 7]])

下圖是對ndarray各種屬性的一個小結


 

5 ndarray陣列的切片和索引

  • 一維陣列

一維陣列的切片和索引與pythonlist索引類似。

1.         a =  np.arange(7)

2.         a

1.         array([0, 1, 2, 3, 4, 5, 6])

1.         a[1:4]

1.         array([1, 2, 3])

1.         # 每間隔2個取一個數

2.         a[ : 6: 2]

1.         array([0, 2, 4])

  • 二維陣列的切片和索引,如下所示:


 

插播一條硬廣:技術文章轉發太多。本文涉及的程式碼量比較多,如需要檢視原始碼,請在微信公眾號“Python資料之道IDPyDataRoad)後臺回覆關鍵字“2017026”

6 處理陣列形狀

6.1 形狀轉換

  • reshape()resize()

1.         b.reshape(4,3)

1.         array([[ 0,  1,  2],

2.                [ 3,  4,  5],

3.                [ 6,  7,  8],

4.                [ 9, 10, 11]])

1.         b

1.         array([[ 0,  1,  2,  3],

2.                [ 4,  5,  6,  7],

3.                [ 8,  9, 10, 11]])

1.         b.resize(4,3)

2.         b

1.         array([[ 0,  1,  2],

2.                [ 3,  4,  5],

3.                [ 6,  7,  8],

4.                [ 9, 10, 11]])

函式resize()的作用跟reshape()類似,但是會改變所作用的陣列,相當於有inplace=True的效果

  • ravel()flatten(),將多維陣列轉換成一維陣列,如下:

1.         b.ravel()

1.         array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

1.         b.flatten()

1.         array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

1.         b

1.         array([[ 0,  1,  2],

2.                [ 3,  4,  5],

3.                [ 6,  7,  8],

4.                [ 9, 10, 11]])

兩者的區別在於返回複製(copy)還是返回檢視(viewflatten()返回一份複製,需要分配新的記憶體空間,對複製所做的修改不會影響原始矩陣,而ravel()返回的是檢視(view),會影響原始矩陣。

參考如下程式碼:


 

  • tuple指定陣列的形狀,如下:

1.         b.shape=(2,6)

2.         b

1.         array([[ 0,  1, 20,  3,  4,  5],

2.                [ 6,  7,  8,  9, 10, 11]])

  • 轉置

前面描述了陣列轉置的屬性(T),也可以透過transpose()函式來實現

1.         b.transpose()

1.         array([[ 0,  6],

2.                [ 1,  7],

3.                [20,  8],

4.                [ 3,  9],

5.                [ 4, 10],

6.                [ 5, 11]])

6.2 堆疊陣列

1.         b

1.         array([[ 0,  1, 20,  3,  4,  5],

2.                [ 6,  7,  8,  9, 10, 11]])

1.         c = b*2

2.         c

1.         array([[ 0,  2, 40,  6,  8, 10],

2.                [12, 14, 16, 18, 20, 22]])

  • 水平疊加

hstack()

1.         np.hstack((b,c))

1.         array([[ 0,  1, 20,  3,  4,  5,  0,  2, 40,  6,  8, 10],

2.                [ 6,  7,  8,  9, 10, 11, 12, 14, 16, 18, 20, 22]])

column_stack()函式以列方式對陣列進行疊加,功能類似hstack()

1.         np.column_stack((b,c))

1.         array([[ 0,  1, 20,  3,  4,  5,  0,  2, 40,  6,  8, 10],

2.                [ 6,  7,  8,  9, 10, 11, 12, 14, 16, 18, 20, 22]])

  • 垂直疊加

vstack()

1.         np.vstack((b,c))

1.         array([[ 0,  1, 20,  3,  4,  5],

2.                [ 6,  7,  8,  9, 10, 11],

3.                [ 0,  2, 40,  6,  8, 10],

4.                [12, 14, 16, 18, 20, 22]])

row_stack()函式以行方式對陣列進行疊加,功能類似vstack()

1.         np.row_stack((b,c))

1.         array([[ 0,  1, 20,  3,  4,  5],

2.                [ 6,  7,  8,  9, 10, 11],

3.                [ 0,  2, 40,  6,  8, 10],

4.                [12, 14, 16, 18, 20, 22]])

  • concatenate()方法,透過設定axis的值來設定疊加方向

axis=1時,沿水平方向疊加

axis=0時,沿垂直方向疊加

1.         np.concatenate((b,c),axis=1)

1.         array([[ 0,  1, 20,  3,  4,  5,  0,  2, 40,  6,  8, 10],

2.                [ 6,  7,  8,  9, 10, 11, 12, 14, 16, 18, 20, 22]])

1.         np.concatenate((b,c),axis=0)

1.         array([[ 0,  1, 20,  3,  4,  5],

2.                [ 6,  7,  8,  9, 10, 11],

3.                [ 0,  2, 40,  6,  8, 10],

4.                [12, 14, 16, 18, 20, 22]])

由於針對陣列的軸為01的方向經常會混淆,透過示意圖,或許可以更好的理解。

關於陣列的軸方向示意圖,以及疊加的示意圖,如下:



  • 深度疊加

這個有點燒腦,舉個例子如下,自己可以體會下:

1.         arr_dstack = np.dstack((b,c))

2.         print(arr_dstack.shape)

3.         arr_dstack

1.         (2, 6, 2)

2.          

3.         array([[[ 0,  0],

4.                 [ 1,  2],

5.                 [20, 40],

6.                 [ 3,  6],

7.                 [ 4,  8],

8.                 [ 5, 10]],

9.          

10.             [[ 6, 12],

11.              [ 7, 14],

12.              [ 8, 16],

13.              [ 9, 18],

14.              [10, 20],

15.              [11, 22]]])

疊加前,bc均是shape為(2,6)的二維陣列,疊加後,arr_dstackshape為(2,6,2)的三維陣列。

深度疊加的示意圖如下:


6.3 陣列的拆分

跟陣列的疊加類似,陣列的拆分可以分為橫向拆分、縱向拆分以及深度拆分。

涉及的函式為 hsplit()vsplit()dsplit() 以及split()

1.         b

1.         array([[ 0,  1, 20,  3,  4,  5],

2.                [ 6,  7,  8,  9, 10, 11]])

  • 沿橫向軸拆分(axis=1

1.         np.hsplit(b, 2)

1.         [array([[ 0,  1, 20],

2.                 [ 6,  7,  8]]), array([[ 3,  4,  5],

3.                 [ 9, 10, 11]])]

1.         np.split(b,2, axis=1)

1.         [array([[ 0,  1, 20],

2.                 [ 6,  7,  8]]), array([[ 3,  4,  5],

3.                 [ 9, 10, 11]])]

  • 沿縱向軸拆分(axis=0

1.         np.vsplit(b, 2)

1.         [array([[ 0,  1, 20,  3,  4,  5]]), array([[ 6,  7,  8,  9, 10, 11]])]

1.         np.split(b,2,axis=0)

1.         [array([[ 0,  1, 20,  3,  4,  5]]), array([[ 6,  7,  8,  9, 10, 11]])]

  • 深度拆分

1.         arr_dstack

1.         array([[[ 0,  0],

2.                 [ 1,  2],

3.                 [20, 40],

4.                 [ 3,  6],

5.                 [ 4,  8],

6.                 [ 5, 10]],

7.          

8.                [[ 6, 12],

9.                 [ 7, 14],

10.              [ 8, 16],

11.              [ 9, 18],

12.              [10, 20],

13.              [11, 22]]])

1.         np.dsplit(arr_dstack,2)

1.         [array([[[ 0],

2.                  [ 1],

3.                  [20],

4.                  [ 3],

5.                  [ 4],

6.                  [ 5]],

7.          

8.                 [[ 6],

9.                  [ 7],

10.               [ 8],

11.               [ 9],

12.               [10],

13.               [11]]]), array([[[ 0],

14.               [ 2],

15.               [40],

16.               [ 6],

17.               [ 8],

18.               [10]],

19.       

20.              [[12],

21.               [14],

22.               [16],

23.               [18],

24.               [20],

25.               [22]]])]

拆分的結果是原來的三維陣列拆分成為兩個二維陣列。

這個燒腦的拆分過程可以自行分析下~~

7 陣列的型別轉換

  • 陣列轉換成list,使用tolist()

1.         b

1.         array([[ 0,  1, 20,  3,  4,  5],

2.                [ 6,  7,  8,  9, 10, 11]])

1.         b.tolist()

1.         [[0, 1, 20, 3, 4, 5], [6, 7, 8, 9, 10, 11]]

  • 轉換成指定型別,astype()函式

1.         b.astype(float)

1.         array([[  0.,   1.,  20.,   3.,   4.,   5.],

2.                [  6.,   7.,   8.,   9.,  10.,  11.]])

8 numpy常用統計函式

常用的函式如下:

請注意函式在使用時需要指定axis軸的方向,若不指定,預設統計整個陣列。

  • np.sum(),返回求和
  • np.mean(),返回均值
  • np.max(),返回最大值
  • np.min(),返回最小值
  • np.ptp(),陣列沿指定軸返回最大值減去最小值,即(max-min
  • np.std(),返回標準偏差(standard deviation
  • np.var(),返回方差(variance
  • np.cumsum(),返回累加值
  • np.cumprod(),返回累乘積值

1.         b

1.         array([[ 0,  1, 20,  3,  4,  5],

2.                [ 6,  7,  8,  9, 10, 11]])

1.         np.max(b)

1.         20

1.         # 沿axis=1軸方向統計

2.         np.max(b,axis=1)

1.         array([20, 11])

1.         # 沿axis=0軸方向統計

2.         np.max(b,axis=0)

1.         array([ 6,  7, 20,  9, 10, 11])

1.         np.min(b)

1.         0

  • np.ptp(),返回整個陣列的最大值減去最小值,如下:

1.         np.ptp(b)

1.         20

1.         # 沿axis=0軸方向

2.         np.ptp(b, axis=0)

1.         array([ 6,  6, 12,  6,  6,  6])

1.         # 沿axis=1軸方向

2.         np.ptp(b, axis=1)

1.         array([20,  5])

  • np.cumsum(),沿指定軸方向進行累加

1.         b.resize(4,3)

2.         b

1.         array([[ 0,  1, 20],

2.                [ 3,  4,  5],

3.                [ 6,  7,  8],

4.                [ 9, 10, 11]])

1.         np.cumsum(b, axis=1)

1.         array([[ 0,  1, 21],

2.                [ 3,  7, 12],

3.                [ 6, 13, 21],

4.                [ 9, 19, 30]], dtype=int32)

1.         np.cumsum(b, axis=0)

1.         array([[ 0,  1, 20],

2.                [ 3,  5, 25],

3.                [ 9, 12, 33],

4.                [18, 22, 44]], dtype=int32)

  • np.cumprod(),沿指定軸方向進行累乘積 (Return the cumulative product of the elements along the given axis

1.         np.cumprod(b,axis=1)

1.         array([[  0,   0,   0],

2.                [  3,  12,  60],

3.                [  6,  42, 336],

4.                [  9,  90, 990]], dtype=int32)

1.         np.cumprod(b,axis=0)

1.         array([[   0,    1,   20],

2.                [   0,    4,  100],

3.                [   0,   28,  800],

4.                [   0,  280, 8800]], dtype=int32)

9 陣列的廣播

當陣列跟一個標量進行數學運算時,標量需要根據陣列的形狀進行擴充套件,然後執行運算。

這個擴充套件的過程稱為廣播(broadcasting

1.         b

1.         array([[ 0,  1, 20],

2.                [ 3,  4,  5],

3.                [ 6,  7,  8],

4.                [ 9, 10, 11]])

1.         d = b + 2

2.         d

1.         array([[ 2,  3, 22],

2.                [ 5,  6,  7],

3.                [ 8,  9, 10],

4.                [11, 12, 13]])

寫在最後

numpy涵蓋的內容其實是非常豐富的,本文僅僅介紹了numpy一些常用的基本功能,算是對numpy的一個入門級的簡單的較為全面的描述。

numpy官方的《Numpy Reference》文件,光頁面數量就有1500+頁,如想要系統的學習numpy,建議仔細閱讀官方的參考文件,可在其官方網站進行查閱。當然,資料都是英文版的,可能看起來難度稍微大點,看習慣了就好。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29829936/viewspace-2149843/,如需轉載,請註明出處,否則將追究法律責任。

相關文章