根據利用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