Python Numpy 快速入門指導 (一) 基礎

    本文乃Numpy Quickstart tutorial的翻譯版本(並非完全翻譯,翻譯君爲本人),英語能力足夠的童鞋請閱讀原文~,如果您覺得本文對您有幫助的話不要忘記點個贊哦!


一 預先準備    

  在閱讀本文之前,請先確保您已經有了一些python基礎,如果沒有的話,請看Python Tutorial,安裝在此跳過。


二 基礎

    numpy的操作對象通常是齊次的多維數組,數組的每一個元素的類型應當一致(比如全爲int,float等等),numpy中,多維數組的維度被稱爲軸(比如三維數組之於XYZ),軸上以循秩(rank)訪問。

    譬如在三維空間中一個點[1,2,1],該點的座標可以看做是一個rank爲1的數組(一維數組),數組長度3

    而下列所示爲rank=2(二維數組),第一個維度長度爲2,第二個維度長度爲3

[[ 1., 0., 0.],
 [ 0., 1., 2.]]

    Numpy的數組類稱爲ndarray,注意numpy.array和python標準庫中的array並不一樣,後者只提供一維數組及其操作。下面列出numpy的一些重要接口:

    ndarray.ndim
    數組的維度,也稱數組的軸(axes)的數量。
    ndarray.shape
   數組的尺寸。返回一個整數元組,表示數組中每個維度上,數組含有多少元素。對於具有n行m列的矩陣,形狀將是(n,m)。顯然這個元組的長度是數組的維度ndarray.ndim
    ndarray.size
    數組元素的總數。等於數組尺寸中所有值的乘積,對於具有n行m列的矩陣,就是n*m
    ndarray.dtype
    數組中元素的類型。可以使用標準的Python中定義的類型創建,或指定其他的dtype類型。此外,NumPy提供了一些它自己的類型。譬如: numpy.int32,numpy.int16,numpy.float64
    ndarray.itemsize
    數組中每個元素的字節大小。例如,float64類型的元素大小爲8(= 64/8),而complex32類型中的項目大小爲4(= 32/8)。相當於ndarray.dtype.itemsize。
    ndarray.data

    該緩衝區包含數組的實際元素。通常,我們不需要使用它,因爲我們將使用循秩訪問訪問數組中的元素。

例子:

>>> import numpy as np
>>> a = np.arange(15).reshape(3, 5)
>>> a
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
>>> a.shape
(3, 5)
>>> a.ndim
2
>>> a.dtype.name
'int64'
>>> a.itemsize
8
>>> a.size
15
>>> type(a)
<type 'numpy.ndarray'>
>>> b = np.array([6, 7, 8])
>>> b
array([6, 7, 8])
>>> type(b)
<type 'numpy.ndarray'>


三 數組的創建

    下面我們就來介紹如何創建數組。

    方法一:使用python 列表或者元組創建,array的dtype將會取決於您輸入元素的類型。如果您輸入的數字都爲int或者都爲float,那麼array的類型也將是這個。

>>> import numpy as np
>>> a = np.array([2,3,4])
>>> a
array([2, 3, 4])
>>> a.dtype
dtype('int64')
>>> b = np.array([1.2, 3.5, 5.1])
>>> b.dtype
dtype('float64')

    請注意:創建array時請使用[],切勿省略。

>>> a = np.array(1,2,3,4)    # WRONG
>>> a = np.array([1,2,3,4])  # RIGHT

    可以將array轉換成二維數組,形似[array(),array(),array().........]。以同樣的方法可以創建三維,乃至更多維度的數組

>>> b = np.array([(1.5,2,3), (4,5,6)])  # 注意到這裏混用了int和float,最終全部轉換成了float
>>> b
array([[ 1.5,  2. ,  3. ],
       [ 4. ,  5. ,  6. ]])

    在創建時,可以指定元素類型,比如複數類型

>>> c = np.array( [ [1,2], [3,4] ], dtype=complex )
>>> c
array([[ 1.+0.j,  2.+0.j],
       [ 3.+0.j,  4.+0.j]])

    array的初始化:創建完成後數組內部元素是未知的,儘量應當初始化它。下面介紹幾個用於初始化的函數

    1.zeros,創建一個一定大小的,內部元素全部填充爲0的數組

    2.ones,創建一個一定大小的,內部元素全部填充爲1的數組

    3.empty,創建一個一定大小的,內部元素全部爲隨機數的數組,默認類型爲float64

>>> np.zeros( (3,4) )
array([[ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.]])
>>> np.ones( (2,3,4), dtype=np.int16 )                # dtype can also be specified
array([[[ 1, 1, 1, 1],
        [ 1, 1, 1, 1],
        [ 1, 1, 1, 1]],
       [[ 1, 1, 1, 1],
        [ 1, 1, 1, 1],
        [ 1, 1, 1, 1]]], dtype=int16)
>>> np.empty( (2,3) )                                 # uninitialized, output may vary
array([[  3.73603959e-262,   6.02658058e-154,   6.55490914e-260],
       [  5.30498948e-313,   3.14673309e-307,   1.00000000e+000]])

    numpy同樣提供了可以返回範圍的函數,

np.arange( lo, hi, delta )  # 從lo開始直到hi(不包括hi),每隔delta給一個數

>>> np.arange( 10, 30, 5 )
array([10, 15, 20, 25])
>>> np.arange( 0, 2, 0.3 )                 # it accepts float arguments
array([ 0. ,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8])

    numpy也提供了相似功能的函數,這個函數可以規定將lo到hi平分爲多少步走完。

>>> np.linspace( 0, 2, 9 )                 # 9 numbers from 0 to 2
array([ 0.  ,  0.25,  0.5 ,  0.75,  1.  ,  1.25,  1.5 ,  1.75,  2.  ])

    這一函數可以很簡便地用於繪函數圖,並規定精度,代碼如下:

>>> from numpy import pi
>>> x = np.linspace( 0, 2*pi, 100 )        # useful to evaluate function at lots of points
>>> f = np.sin(x)


四 數組的打印

    如果您要打印多維數組,numpy將以如下規則進行:

    1.從左到右打印最後一個維度的元素

    2.從上到下打印倒數第二個軸的元素

    3.剩下的維度一樣從上到下,只不過每一個矩陣都和下一個分開打印

    總之,一維數組打印爲一行,二維數組打印爲一個矩陣,三維數組打印爲矩陣列表

>>> a = np.arange(6)                         # 1d array
>>> print(a)
[0 1 2 3 4 5]
>>>
>>> b = np.arange(12).reshape(4,3)           # 2d array
>>> print(b)
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
>>>
>>> c = np.arange(24).reshape(2,3,4)         # 3d array
>>> print(c)
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]
 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]

    注意:如果數組過於巨大,比如上萬行,上萬列等等。numpy將自動打印邊角的元素

>>> print(np.arange(10000))
[   0    1    2 ..., 9997 9998 9999]
>>>
>>> print(np.arange(10000).reshape(100,100))
[[   0    1    2 ...,   97   98   99]
 [ 100  101  102 ...,  197  198  199]
 [ 200  201  202 ...,  297  298  299]
 ...,
 [9700 9701 9702 ..., 9797 9798 9799]
 [9800 9801 9802 ..., 9897 9898 9899]
 [9900 9901 9902 ..., 9997 9998 9999]]

    要禁止numpy這麼做,強制打印整個數組,可以輸入下列內容以禁止打印角點。

>>> np.set_printoptions(threshold='nan')


五 基礎操作    

     1.數組的運算。當進行數組的運算時,將會創建一個新的數組來保存運算結果。

    相同大小的數組之間可以進行:

        (1)加減操作,每個元素都被加減;

        (2)平方(寫作**),sin()等函數操作,其中的每個元素都進行該運算,並填入結果中

        (3)bool運算,每個元素都進行這樣的判斷,在結果中填入T/F

>>> a = np.array( [20,30,40,50] )
>>> b = np.arange( 4 )
>>> b
array([0, 1, 2, 3])
>>> c = a-b
>>> c
array([20, 29, 38, 47])
>>> b**2
array([0, 1, 4, 9])
>>> 10*np.sin(a)
array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])
>>> a<35
array([ True, True, False, False], dtype=bool)

    numpy中,*表示數組對應位置的元素相乘,矩陣乘法要使用.dot()方法

>>> A = np.array( [[1,1],
...             [0,1]] )
>>> B = np.array( [[2,0],
...             [3,4]] )
>>> A*B                         # elementwise product 元素乘法,對應位置相乘
array([[2, 0],
       [0, 4]])
>>> A.dot(B)                    # matrix product 矩陣乘法
array([[5, 4],
       [3, 4]])
>>> np.dot(A, B)                # another matrix product 另一種進行矩陣乘法的方式
array([[5, 4],
       [3, 4]])

    比如+=,-=,*=,/=的操作,將會在原來的數組上進行,並不會創建一個新的數組保存結果,因此不能將兩種不同類型的元素相操作。

>>> a = np.ones((2,3), dtype=int)
>>> b = np.random.random((2,3))
>>> a *= 3
>>> a
array([[3, 3, 3],
       [3, 3, 3]])
>>> b += a
>>> b
array([[ 3.417022  ,  3.72032449,  3.00011437],
       [ 3.30233257,  3.14675589,  3.09233859]])
>>> a += b                  # b is not automatically converted to integer type
Traceback (most recent call last):
  ...
TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int64') with casting rule 'same_kind'

    對於那些創建新的數組來保存結果的運算,當兩種不同類型的元素運算時,結果自動變成兩種中更精確那種類型,比如float+complex->complex

>>> a = np.ones(3, dtype=np.int32)
>>> b = np.linspace(0,pi,3)
>>> b.dtype.name
'float64'
>>> c = a+b
>>> c
array([ 1.        ,  2.57079633,  4.14159265])
>>> c.dtype.name
'float64'
>>> d = np.exp(c*1j)
>>> d
array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
       -0.54030231-0.84147098j])
>>> d.dtype.name
'complex128'

    numpy提供求所有元素的sum(),min(),max(),mean()等一元運算,這些都需要調用numpy,這些操作默認是對數組的一切元素進行,不論數組的形狀,維度

>>> a = np.random.random((2,3))
>>> a
array([[ 0.18626021,  0.34556073,  0.39676747],
       [ 0.53881673,  0.41919451,  0.6852195 ]])
>>> a.sum()
2.5718191614547998
>>> a.min()
0.1862602113776709
>>> a.max()
0.6852195003967595
>>> a = np.array([[1, 2], [3, 4]])
>>> np.mean(a)
2.5

    如果要對特定的維度上進行上述操作,請指定維度,即sum(axis= ),注意軸的序列是列axis=0,行axis=1。

>>> b = np.arange(12).reshape(3,4)
>>> b
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>>
>>> b.sum(axis=0)                            # sum of each column
array([12, 15, 18, 21])
>>>
>>> b.min(axis=1)                            # min of each row
array([0, 4, 8])
>>>
>>> b.cumsum(axis=1)                         # cumulative sum along each row
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]])
>>> a = np.array([[1, 2], [3, 4]])
>>> np.mean(a)
2.5
>>> np.mean(a, axis=0)
array([ 2.,  3.])
>>> np.mean(a, axis=1)
array([ 1.5,  3.5])

    其他操作:numpy還支持sin cos exp sqrt等常規函數,這些函數對數組裏的所有元素進行操作

>>> B = np.arange(3)
>>> B
array([0, 1, 2])
>>> np.exp(B)
array([ 1.        ,  2.71828183,  7.3890561 ])
>>> np.sqrt(B)
array([ 0.        ,  1.        ,  1.41421356])
>>> C = np.array([2., -1., 4.])
>>> np.add(B, C)
array([ 2.,  0.,  6.])

六 對數組的切片,循秩訪問,和迭代

    一維數組可以被切片,循秩訪問,迭代,這和python的list相似

>>> a = np.arange(10)**3
>>> a
array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729])
>>> a[2]
8
>>> a[2:5]
array([ 8, 27, 64])
>>> a[:6:2] = -1000    # equivalent to a[0:6:2] = -1000; from start to position 6, exclusive, set every 2nd element to -1000
>>> a
array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,   729])
>>> a[ : :-1]                                 # reversed a
array([  729,   512,   343,   216,   125, -1000,    27, -1000,     1, -1000])
>>> for i in a:
...     print(i**(1/3.))
...
nan
1.0
nan
3.0
nan
5.0
6.0
7.0
8.0
9.0
    多維數組的元素具有一個多維的索引,通過元組[a,b],(a行b列,ab均爲0-index)可以訪問之,切片也是一樣

>>> def f(x,y):
...     return 10*x+y
...
>>> b = np.fromfunction(f,(5,4),dtype=int)
>>> b
array([[ 0,  1,  2,  3],
       [10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33],
       [40, 41, 42, 43]])
>>> b[2,3]
23
>>> b[0:5, 1]                       # each row in the second column of b
array([ 1, 11, 21, 31, 41])
>>> b[ : ,1]                        # equivalent to the previous example
array([ 1, 11, 21, 31, 41])
>>> b[1:3, : ]                      # each column in the second and third row of b
array([[10, 11, 12, 13],
       [20, 21, 22, 23]])

    如果輸入的引索值不夠,則剩下的默認爲所有(:)

>>> b[-1]                                  # the last row. Equivalent to b[-1,:]   
#  維度取值應當爲0-n的值,但是python允許超過這個範圍,並且取出mod n 的秩 ,-1表示最後一行
array([40, 41, 42, 43])

    如果覺得太多的:,:,:麻煩,可以用...(三個點)代替,其中的維度將使用盡量多的:,代替。

    比如B[1,...],則代表第一片矩陣的全部。

>>> c = np.array( [[[  0,  1,  2],               # a 3D array (two stacked 2D arrays)
...                 [ 10, 12, 13]],
...                [[100,101,102],
...                 [110,112,113]]])
>>> c.shape
(2, 2, 3)
>>> c[1,...]                                   # same as c[1,:,:] or c[1]
array([[100, 101, 102],
       [110, 112, 113]])
>>> c[...,2]                                   # same as c[:,:,2]
array([[  2,  13],
       [102, 113]])

    多維數組可以進行迭代,但是是對第一個維度進行

>>> for row in b:
...     print(row)
...
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]

    如果想要對多維數組的全部元素進行迭代,可以使用flat

>>> for element in b.flat:
...     print(element)
...
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43

    第一部分到此結束,如果覺得這一部分對您有幫助的話,請點贊。如果我的翻譯哪裏不妥,還請指出。

                                                                                                                 2018/3/23


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章