numpy

根據利用Python進行數據分析·第2版中的numpy部分選取一些覺得需要記住的點
簡書:https://www.jianshu.com/p/a380222a3292

ndarray的數據類型

dtype(數據類型)是一個特殊的對象,它含有ndarray將一塊內存解釋爲特定數據類型所需的信息:

dtype是NumPy靈活交互其它系統的源泉之一。多數情況下,它們直接映射到相應的機器表示,這使得“讀寫磁盤上的二進制數據流”以及“集成低級語言代碼(如C、Fortran)”等工作變得更加簡單。

ndarray的具體數據類型有:
這裏寫圖片描述
這裏寫圖片描述
注意:使用numpy.string_類型時,一定要小心,因爲NumPy的字符串數據是大小固定的,發生截取時,不會發出警告。

你可以通過ndarray的astype方法明確地將一個數組從一個dtype轉換成另一個dtype:
這個在使用某些方法(對數據類型有要求的方法的時候)有良好效果
調用astype總會創建一個新的數組(一個數據的備份),即使新的dtype與舊的dtype相同。

對於ndarray
當你將一個標量值賦值給一個切片時(如arr[5:8]=12),該值會自動傳播(也就說後面將會講到的“廣播”)到整個選區。跟列表最重要的區別在於,數組切片是原始數組的視圖。這意味着數據不會被複制,視圖上的任何修改都會直接反映到源數組上。

作爲例子,先創建一個arr的切片:

in: arr
out: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [64]: arr[5:8] = 12
In [66]: arr_slice = arr[5:8]

In [65]: arr
Out[65]: array([ 0,  1,  2,  3,  4, 12, 12, 12,  8,  9])

In [67]: arr_slice
Out[67]: array([12, 12, 12])

現在,當我修稿arr_slice中的值,變動也會體現在原始數組arr中:

In [68]: arr_slice[1] = 12345

In [69]: arr
Out[69]: 
array([0,1,2,3,4,12,12345,12,8,9])

切片[ : ]會給數組中的所有值賦值:

In [70]: arr_slice[:] = 64

In [71]: arr
Out[71]: array([ 0,  1,  2,  3,  4, 64, 64, 64,  8,  9])

注意:如果你想要得到的是ndarray切片的一份副本而非視圖,就需要明確地進行復制操作,例如arr[5:8].copy()。

布爾值索引

In [98]: 
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])

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

In [100]: names
Out[100]: 
array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'],
      dtype='<U4')

In [101]: data
Out[101]: 
array([[ 0.0929,  0.2817,  0.769 ,  1.2464],
       [ 1.0072, -1.2962,  0.275 ,  0.2289],
       [ 1.3529,  0.8864, -2.0016, -0.3718],
       [ 1.669 , -0.4386, -0.5397,  0.477 ],
       [ 3.2489, -1.0212, -0.5771,  0.1241],
       [ 0.3026,  0.5238,  0.0009,  1.3438],
       [-0.7135, -0.8312, -2.3702, -1.8608]])

假設每個名字都對應data數組中的一行,而我們想要選出對應於名字”Bob”的所有行。跟算術運算一樣,數組的比較運算(如==)也是矢量化的。因此,對names和字符串”Bob”的比較運算將會產生一個布爾型數組:

In [102]: names == 'Bob' 
Out[102]: 
array([ True, False, False,  True, False, False, False], dtype=bool)

這個布爾型數組可用於數組索引:

In [103]: data[names == 'Bob']
Out[103]: 
array([[ 0.0929,  0.2817,  0.769 ,  1.2464],
       [ 1.669 , -0.4386, -0.5397,  0.477 ]])

布爾型數組的長度必須跟被索引的軸長度一致。此外,還可以將布爾型數組跟切片、整數(或整數序列,稍後將對此進行詳細講解)混合使用:

In [103]: data[names == 'Bob']
Out[103]: 
array([[ 0.0929,  0.2817,  0.769 ,  1.2464],
       [ 1.669 , -0.4386, -0.5397,  0.477 ]])

注意:如果布爾型數組的長度不對,布爾型選擇就會出錯,因此一定要小心。

我選取了names == ‘Bob’的行,並索引了列:

In [104]: data[names == 'Bob', 2:]
Out[104]: 
array([[ 0.769 ,  1.2464],
       [-0.5397,  0.477 ]])

In [105]: data[names == ‘Bob’, 3]
Out[105]: array([ 1.2464, 0.477 ])
要選擇除”Bob”以外的其他值,既可以使用不等於符號(!=),也可以通過~對條件進行否定:

In [106]: names != 'Bob'
Out[106]: array([False,  True,  True, False,  True,  True,  True], dtype=bool)

In [107]: data[~(names == 'Bob')]
Out[107]:
array([[ 1.0072, -1.2962,  0.275 ,  0.2289],
       [ 1.3529,  0.8864, -2.0016, -0.3718],
       [ 3.2489, -1.0212, -0.5771,  0.1241],
       [ 0.3026,  0.5238,  0.0009,  1.3438],
       [-0.7135, -0.8312, -2.3702, -1.8608]])

~操作符用來反轉條件很好用:

In [108]: cond = names == 'Bob'

In [109]: data[~cond]
Out[109]: 
array([[ 1.0072, -1.2962,  0.275 ,  0.2289],
       [ 1.3529,  0.8864, -2.0016, -0.3718],
       [ 3.2489, -1.0212, -0.5771,  0.1241],
       [ 0.3026,  0.5238,  0.0009,  1.3438],
       [-0.7135, -0.8312, -2.3702, -1.8608]])

選取這三個名字中的兩個需要組合應用多個布爾條件,使用&(和)、|(或)之類的布爾算術運算符即可:

In [110]: mask = (names == 'Bob') | (names == 'Will')

In [111]: mask
Out[111]: 
array([ True, False,  True,  True,  True, False, False], dtype=bool)

In [112]: data[mask]
Out[112]: 
array([[ 0.0929,  0.2817,  0.769 ,  1.2464],
       [ 1.3529,  0.8864, -2.0016, -0.3718],
       [ 1.669 , -0.4386, -0.5397,  0.477 ],
       [ 3.2489, -1.0212, -0.5771,  0.1241]])

通過布爾型索引選取數組中的數據,將總是創建數據的副本,即使返回一模一樣的數組也是如此。

注意:Python關鍵字and和or在布爾型數組中無效。要使用&與|。

通過布爾型數組設置值是一種經常用到的手段。爲了將data中的所有負值都設置爲0,我們只需:

In [113]: data[data < 0] = 0

In [114]: data
Out[114]: 
array([[ 0.0929,  0.2817,  0.769 ,  1.2464],
       [ 1.0072,  0.    ,  0.275 ,  0.2289],
       [ 1.3529,  0.8864,  0.    ,  0.    ],
       [ 1.669 ,  0.    ,  0.    ,  0.477 ],
       [ 3.2489,  0.    ,  0.    ,  0.1241],
       [ 0.3026,  0.5238,  0.0009,  1.3438],
       [ 0.    ,  0.    ,  0.    ,  0.    ]])

通過一維布爾數組設置整行或列的值也很簡單:

In [115]: data[names != 'Joe'] = 7

In [116]: data
Out[116]: 
array([[ 7.    ,  7.    ,  7.    ,  7.    ],
       [ 1.0072,  0.    ,  0.275 ,  0.2289],
       [ 7.    ,  7.    ,  7.    ,  7.    ],
       [ 7.    ,  7.    ,  7.    ,  7.    ],
       [ 7.    ,  7.    ,  7.    ,  7.    ],
       [ 0.3026,  0.5238,  0.0009,  1.3438],
       [ 0.    ,  0.    ,  0.    ,  0.    ]])

後面會看到,這類二維數據的操作也可以用pandas方便的來做。

花式索引

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

爲了以特定順序選取行子集,只需傳入一個用於指定順序的整數列表或ndarray即可:

In [120]: arr[[4, 3, 0, 6]]
Out[120]: 
array([[ 4.,  4.,  4.,  4.],
       [ 3.,  3.,  3.,  3.],
       [ 0.,  0.,  0.,  0.],
       [ 6.,  6.,  6.,  6.]])

一次傳入多個索引數組會有一點特別。它返回的是一個一維數組,其中的元素對應各個索引元組:

In [122]: arr = np.arange(32).reshape((8, 4))

In [123]: arr
Out[123]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23],
       [24, 25, 26, 27],
       [28, 29, 30, 31]])

In [124]: arr[[1, 5, 7, 2], [0, 3, 1, 2]]
Out[124]: array([ 4, 23, 29, 10])

最終選出的是元素(1,0)、(5,3)、(7,1)和(2,2)。無論數組是多少維的,花式索引總是一維的。

這個花式索引的行爲可能會跟某些用戶的預期不一樣(包括我在內),選取矩陣的行列子集應該是矩形區域的形式纔對。下面是得到該結果的一個辦法:

In [125]: arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]]
Out[125]: 
array([[ 4,  7,  5,  6],
       [20, 23, 21, 22],
       [28, 31, 29, 30],
       [ 8, 11,  9, 10]])

記住,花式索引跟切片不一樣,它總是將數據複製到新數組中。

數組轉置和軸對換

矩陣轉置:ndarry.T
計算內積:np.dot()
對於高維數組,transpose需要得到一個由軸編號組成的元組才能對這些軸進行轉置(比較費腦子):

In [132]: arr = np.arange(16).reshape((2, 2, 4))

In [133]: arr
Out[133]: 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],
       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])

In [134]: arr.transpose((1, 0, 2))
Out[134]: 
array([[[ 0,  1,  2,  3],
        [ 8,  9, 10, 11]],
       [[ 4,  5,  6,  7],
        [12, 13, 14, 15]]])

這裏,第一個軸被換成了第二個,第二個軸被換成了第一個,最後一個軸不變。

簡單的轉置可以使用.T,它其實就是進行軸對換而已。ndarray還有一個swapaxes方法,它需要接受一對軸編號:

In [135]: arr
Out[135]: 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],
       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])

In [136]: arr.swapaxes(1, 2)
Out[136]: 
array([[[ 0,  4],
        [ 1,  5],
        [ 2,  6],
        [ 3,  7]],
       [[ 8, 12],
        [ 9, 13],
        [10, 14],
        [11, 15]]])

swapaxes也是返回源數據的視圖(不會進行任何複製操作)。

通用函數:快速的元素級數組函數

這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

將條件邏輯表述爲數組運算

numpy.where函數是三元表達式x if condition else y的矢量化版本。假設我們有一個布爾數組和兩個值數組:

In [165]: xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])

In [166]: yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])

In [167]: cond = np.array([True, False, True, True, False])

假設我們想要根據cond中的值選取xarr和yarr的值:當cond中的值爲True時,選取xarr的值,否則從yarr中選取。列表推導式的寫法應該如下所示:

In [168]: result = [(x if c else y)
   .....:           for x, y, c in zip(xarr, yarr, cond)]

In [169]: result
Out[169]: [1.1000000000000001, 2.2000000000000002, 1.3, 1.3999999999999999, 2.5]

這有幾個問題。第一,它對大數組的處理速度不是很快(因爲所有工作都是由純Python完成的)。第二,無法用於多維數組。若使用np.where,則可以將該功能寫得非常簡潔:

In [170]: result = np.where(cond, xarr, yarr)

In [171]: result
Out[171]: array([ 1.1,  2.2,  1.3,  1.4,  2.5])

np.where的第二個和第三個參數不必是數組,它們都可以是標量值。在數據分析工作中,where通常用於根據另一個數組而產生一個新的數組。假設有一個由隨機數據組成的矩陣,你希望將所有正值替換爲2,將所有負值替換爲-2。若利用np.where,則會非常簡單:

In [172]: arr = np.random.randn(4, 4)

In [173]: arr
Out[173]: 
array([[-0.5031, -0.6223, -0.9212, -0.7262],
       [ 0.2229,  0.0513, -1.1577,  0.8167],
       [ 0.4336,  1.0107,  1.8249, -0.9975],
       [ 0.8506, -0.1316,  0.9124,  0.1882]])

In [174]: arr > 0
Out[174]: 
array([[False, False, False, False],
       [ True,  True, False,  True],
       [ True,  True,  True, False],
       [ True, False,  True,  True]], dtype=bool)

In [175]: np.where(arr > 0, 2, -2)
Out[175]: 
array([[-2, -2, -2, -2],
       [ 2,  2, -2,  2],
       [ 2,  2,  2, -2],
       [ 2, -2,  2,  2]])

使用np.where,可以將標量和數組結合起來。例如,我可用常數2替換arr中所有正的值:

In [176]: np.where(arr > 0, 2, arr) # set only positive values to 2
Out[176]: 
array([[-0.5031, -0.6223, -0.9212, -0.7262],
       [ 2.    ,  2.    , -1.1577,  2.    ],
       [ 2.    ,  2.    ,  2.    , -0.9975],
       [ 2.    , -0.1316,  2.    ,  2.    ]])

傳遞給where的數組大小可以不相等,甚至可以是標量值。

數學和統計方法

在多維數組中,累加函數(如cumsum),累乘函數(如cumprod)返回的是同樣大小的數組,但是會根據每個低維的切片沿着標記軸計算部分聚類:

In [186]: arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])

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

In [188]: arr.cumsum(axis=0)
Out[188]: 
array([[ 0,  1,  2],
       [ 3,  5,  7],
       [ 9, 12, 15]])

In [189]: arr.cumprod(axis=1)
Out[189]: 
array([[  0,   0,   0],
       [  3,  12,  60],
       [  6,  42, 336]])

這裏寫圖片描述

這裏寫圖片描述

用於布爾型數組的方法

在上面這些方法中,布爾值會被強制轉換爲1(True)和0(False)。因此,sum經常被用來對布爾型數組中的True值計數:

In [190]: arr = np.random.randn(100)

In [191]: (arr > 0).sum() # Number of positive values
Out[191]: 42
另外還有兩個方法any和all,它們對布爾型數組非常有用。any用於測試數組中是否存在一個或多個True,而all則檢查數組中所有值是否都是True:

In [192]: bools = np.array([False, False, True, False])

In [193]: bools.any()
Out[193]: True

In [194]: bools.all()
Out[194]: False
這兩個方法也能用於非布爾型數組,所有非0元素將會被當做True。

唯一化以及其它的集合邏輯

這裏寫圖片描述

線性代數方法

這裏寫圖片描述

詳解np.argpartition

https://blog.csdn.net/weixin_37722024/article/details/64440133

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