Numpy最重要的一個特色就是其N維數組對象(即ndarry),該對象是一個快速而靈活的大數據集容器。你能夠利用這種數組對整塊數據執行一些數學運算,其語法跟標量元素之間的運算同樣:python
In [52]: data=np.array([[1,2,3],[4,5,6]]) In [53]: data Out[53]: array([[1, 2, 3], [4, 5, 6]]) In [54]: data*10 Out[54]: array([[10, 20, 30], [40, 50, 60]]) In [55]: data+data Out[55]: array([[ 2, 4, 6], [ 8, 10, 12]])
ndarry是一個通用的同構數據多維容器,也就是說,其中的全部元素必須是相同類型的。每一個數組都有一個shape(一個表示維度大小的元組)和一個dtype(一個說明數組數據類型的對象):數組
In [56]: data.shape Out[56]: (2, 3) In [57]: data.dtype Out[57]: dtype('int32')
建立數組的最簡單辦法就是使用array函數。它接受一切序列型對象(包括其餘數組),而後產生一個新的含有傳入數據的Numpy數組。安全
In [59]: data1=[6,7.8,8,0,True] In [60]: arr1=np.array(data1) In [61]: arr1 Out[61]: array([6. , 7.8, 8. , 0. , 1. ])
嵌套序列(好比由一組等長列表組成的列表)將會被轉換爲一個多維數組:dom
In [62]: data2=[[1,2,3,4],[5,6,7,8]] In [63]: arr2=np.array(data2) In [64]: arr2 Out[64]: array([[1, 2, 3, 4], [5, 6, 7, 8]]) In [65]: arr2.ndim Out[65]: 2 In [66]: arr2.shape Out[66]: (2, 4)
除非顯示說明,np.array會嘗試爲新建的這個數組推斷出一個較爲合適的數據類型。數據類型會保存在一個特殊的dtype對象中。ide
In [69]: arr1.dtype Out[69]: dtype('float64') In [70]: arr2.dtype Out[70]: dtype('int32')
除np.array外,還有一些函數也能夠新建數組。例如,zeros和ones分別能夠建立指定長度或形狀的全0或全1數組。empty能夠建立一個沒有任何具體指的數組。要用這些方法建立多維數組,只須要傳入一個表示形狀的元組便可:函數
In [73]: np.zeros(10) Out[73]: array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) In [74]: np.zeros((3,6)) Out[74]: array([[0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.]]) In [75]: np.empty((2,3,2)) Out[75]: array([[[6.23042070e-307, 4.67296746e-307], [1.69121096e-306, 8.90101523e-307], [1.55762979e-307, 1.78022342e-306]], [[8.06635958e-308, 1.86921415e-306], [1.27946330e-307, 1.11262266e-307], [1.00133162e-307, 1.22387381e-307]]])
注意:認爲np.empty會返回全0數組的想法是不安全的。不少狀況下,它返回的都是一些未初始化的垃圾值。性能
arange是python內置函數range的數組版:大數據
In [76]: np.arange(15) Out[76]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
數組建立函數:ui
array:將輸入數據(列表 元組 數組或其餘序列類型)轉換未ndarry。要麼推斷出dtype,要麼顯示指定dtype。默認執行復制輸入數據。this
asarry:將輸入轉換未ndarry,若是輸入自己就是一個ndarry就不進行復制。
arange:相似與內置的range,返回的是一個ndarry而不是列表
ones丶ones_like:根據指定的形狀和dtype建立一個全1數組。ones_like以另一個數組爲參數,並根據其形狀和dtype建立一個全1數組。
zeros丶zeros_like:相似ones丶ones_like,不過產生的是全0數組。
empty丶empty:建立新數組,只分配內存空間但不填充任何值。
eyp丶identity:建立一個正方的N x N單位矩陣(對角線爲1,其他爲0)
dtype是一個特殊的對象,它含有ndarry將一塊內存解釋爲特定數據類型所需的信息:
它包含的數據類型:int8丶uint8丶int16丶unit16丶int32丶uint32丶int64丶uint64丶float16丶float32丶float64丶float128丶bool等
能夠經過ndarry的astype方法顯式地轉換其dtype:
In [78]: arr=np.array([1,2,3,4,5]) In [79]: arr.dtype Out[79]: dtype('int32') In [80]: float_arr=arr.astype(np.float64) In [81]: float_arr.dtype Out[81]: dtype('float64')
數組很重要,由於你使它不用編寫循環便可對數組執行批量運算,這一般就叫矢量化。
In [83]: arr=np.array([[1,2,3],[4,5,6]]) In [84]: arr Out[84]: array([[1, 2, 3], [4, 5, 6]]) In [85]: arr*arr Out[85]: array([[ 1, 4, 9], [16, 25, 36]]) In [86]: arr -arr Out[86]: array([[0, 0, 0], [0, 0, 0]]) In [87]: 1/arr Out[87]: array([[1. , 0.5 , 0.33333333], [0.25 , 0.2 , 0.16666667]]) In [88]: arr ** 2 Out[88]: array([[ 1, 4, 9], [16, 25, 36]], dtype=int32)
一維數組選取數據子集或單個元素的方式跟python列表功能差很少:
In [90]: arr Out[90]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) In [91]: arr[5] Out[91]: 5 In [92]: arr[5:8] Out[92]: array([5, 6, 7])
當in將一個標量值賦值給一個切片時(如arr[5:8]=12),該值會自動傳播到整個選區,也就是廣播。跟列表最重要的區別在於,數組切片是原始數組的視圖。這意味着數據不會被複制,視圖上任何修改都會直接反映到源數組上:
In [94]: arr Out[94]: array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9]) In [95]: arr_slice=arr[5:8] In [96]: arr_slice[1] Out[96]: 12 In [97]: arr_slice[1]=12345 In [98]: arr Out[98]: array([ 0, 1, 2, 3, 4, 12, 12345, 12, 8, 9]) In [99]: arr_slice[:]=64 In [100]: arr Out[100]: array([ 0, 1, 2, 3, 4, 64, 64, 64, 8, 9])
因爲Numpy的設計目的是處理大數據,能夠想象下加入numpy堅持將數據複製來複制去的話會產生什麼樣的性能和內存問題。若是你想要獲得的是ndarry切片的一份副本而非視圖,就須要顯式的進行復制操做,例如arr[5:8].copy() 。
在一個二維數組中,各索引位置上的元素再也不是標量而是一維數組:
In [101]: arr2=np.array([[1,2,3],[4,5,6],[7,8,9]]) In [102]: arr2[2] Out[102]: array([7, 8, 9])
所以,能夠對多個元素進行遞歸訪問,,也能夠傳入一個逗號隔開的索引列表來選取單個元素,兩種方式是等價的:
In [109]: arr2[0][2] Out[109]: 3 In [110]: arr2[0,2] Out[110]: 3
在多維數組中,若是省略了後面的索引,則返回對象是一個維度低一點的ndarry。
In [111]: arr3d=np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]) In [112]: arr3d Out[112]: array([[[ 1, 2, 3], [ 4, 5, 6]], [[ 7, 8, 9], [10, 11, 12]]])
arr3d是一個2x3的數組
In [113]: arr3d[0] Out[113]: array([[1, 2, 3], [4, 5, 6]])
標量值和數組均可以被賦值給arr3d[0]:
In [114]: old_values=arr3d[0].copy() In [115]: arr3d[0]=42 In [116]: arr3d Out[116]: array([[[42, 42, 42], [42, 42, 42]], [[ 7, 8, 9], [10, 11, 12]]]) In [117]: arr3d[0]=old_values In [118]: arr3d Out[118]: array([[[ 1, 2, 3], [ 4, 5, 6]], [[ 7, 8, 9], [10, 11, 12]]])
以此類推,arr3d[1,0]能夠訪問索引以(1,0)開頭的那些值:
In [119]: arr3d[1,0] Out[119]: array([7, 8, 9])
注意:上面全部這些選取數組子集的例子中,返回的數組都是視圖。
ndarry的切片語法跟python列表這樣的一維對象差很少:
In [120]: arr[1:6] Out[120]: array([ 1, 2, 3, 4, 64])
高維度對象的花樣更多,你能夠子啊一個或多個軸上進行切片,也能夠跟整數索引混合使用。
In [122]: arr2d=np.array([[1,2,3],[4,5,6],[7,8,9]]) In [123]: arr2d Out[123]: array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) In [124]: arr2d[:2] Out[124]: array([[1, 2, 3], [4, 5, 6]])
能夠看出,它是沿着第0軸切片的。也就是說切片是沿着一個軸向選取元素的。你能夠一次傳入多個切片,就像傳入多個索引那樣:
In [125]: arr2d[:2,1:] Out[125]: array([[2, 3], [5, 6]])
像這樣進行切片時,只能獲得相同維度的數組視圖。經過將整數索引和切片混合,能夠獲得低維度的切片:
In [127]: arr2d[1,:2] Out[127]: array([4, 5]) In [128]: arr2d[2,:1] Out[128]: array([7])
注意:只有冒號表示選取整個軸:、
In [129]: arr2d[:,:1] Out[129]: array([[1], [4], [7]])
天然,對切片表達式的賦值操做也會被擴散到整個選區:
In [130]: arr2d[:2,1:] Out[130]: array([[2, 3], [5, 6]]) In [131]: arr2d[:2,1:]=0 In [132]: arr2d Out[132]: array([[1, 0, 0], [4, 0, 0], [7, 8, 9]])
假設咱們有一個用於存儲數據的數組以及一個存儲姓名的數組(含有重複項)。在這裏,咱們將使用numpy.random中的randn函數生成一些正態分佈的隨機數據:
In [133]: names=np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe']) In [134]: data=randn(7,4) In [135]: names Out[135]: array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='<U4') In [136]: data Out[136]: array([[ 1.49700553, -0.81010655, 1.38541267, 0.77762598], [-1.04760513, -0.25802261, -0.07125992, -0.03431114], [-0.49107174, -1.33574227, 0.10408644, -0.46662551], [ 0.71487411, 1.18651842, -0.34714216, 0.46087672], [ 0.2254356 , 0.76541494, 0.12525111, -0.92919057], [-1.20091987, 0.37064336, -0.77465353, 0.43543748], [ 2.63967324, -0.7687978 , 0.78363981, 0.02063025]])
假設每一個名字對應data數組的一行,而咱們想選粗話對應與名字'Bob'的全部行。跟算術運算同樣,數組的比較運算(如==)也是矢量化的。所以,對names和字符串‘Bob’的比較運算將會產生一個布爾型數組:
n [137]: names=='Bob' Out[137]: array([ True, False, False, True, False, False, False])
這個布爾型數組可用於數組索引:
In [139]: data[names=='Bob'] Out[139]: array([[ 1.49700553, -0.81010655, 1.38541267, 0.77762598], [ 0.71487411, 1.18651842, -0.34714216, 0.46087672]])
布爾型數組的長度必須跟被索引的軸長度同樣。所以,還能夠將布爾型數組跟切片丶整數混合使用:
In [140]: data[names=='Bob',2:] Out[140]: array([[ 1.38541267, 0.77762598], [-0.34714216, 0.46087672]])
In [141]: data[names=='Bob',3]
Out[141]: array([0.77762598, 0.46087672])
要選擇除"Bob"之外的其餘值,既可使用不等於符號(!=),也能夠經過符號(-)對條件進行否認:
In [141]: data[names=='Bob',3] Out[141]: array([0.77762598, 0.46087672])
In [151]: data[~(names == 'Bob')]
Out[151]:
array([[-1.04760513, -0.25802261, -0.07125992, -0.03431114],
[-0.49107174, -1.33574227, 0.10408644, -0.46662551],
[ 0.2254356 , 0.76541494, 0.12525111, -0.92919057],
[-1.20091987, 0.37064336, -0.77465353, 0.43543748],
[ 2.63967324, -0.7687978 , 0.78363981, 0.02063025]])
這裏試了下使用符號(-)會報錯TypeError: The numpy boolean negative, the `-` operator, is not supported, use the `~` operator or the logical_not function instead.提示,須要使用~符號表示取反
選取這3個名字中的2個須要組合應用多個布爾條件,使用&(和)丶|(或)之類的布爾算術運算符便可:
In [152]: mask=(names=='Bob') |(names=='Will') In [153]: mask Out[153]: array([ True, False, True, True, True, False, False])
In [154]: data[mask]
Out[154]:
array([[ 1.49700553, -0.81010655, 1.38541267, 0.77762598],
[-0.49107174, -1.33574227, 0.10408644, -0.46662551],
[ 0.71487411, 1.18651842, -0.34714216, 0.46087672],
[ 0.2254356 , 0.76541494, 0.12525111, -0.92919057]])
經過布爾型索引選取數組中的數據,將老是建立數據的副本,即便返回如出一轍的數組,也是如此。
經過布爾型數組設置值是一種常用的手段。爲了將data中全部的負值設置爲0:
In [155]: data[data<0]=0 In [156]: data Out[156]: array([[1.49700553, 0. , 1.38541267, 0.77762598], [0. , 0. , 0. , 0. ], [0. , 0. , 0.10408644, 0. ], [0.71487411, 1.18651842, 0. , 0.46087672], [0.2254356 , 0.76541494, 0.12525111, 0. ], [0. , 0.37064336, 0. , 0.43543748], [2.63967324, 0. , 0.78363981, 0.02063025]])
經過一維布爾數組設置整行或列的值也很簡單:
In [157]: data[names!='Joe']=7 In [158]: data Out[158]: array([[7. , 7. , 7. , 7. ], [0. , 0. , 0. , 0. ], [7. , 7. , 7. , 7. ], [7. , 7. , 7. , 7. ], [7. , 7. , 7. , 7. ], [0. , 0.37064336, 0. , 0.43543748], [2.63967324, 0. , 0.78363981, 0.02063025]])
花式索引是一個Numpy術語,它指的的是利用整數數組進行索引。假設咱們有個8*4的數組:
In [162]: arr=np.empty((8,4)) In [163]: for i in range(8): ...: arr[i]=i ...: In [164]: arr Out[164]: 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.]])
爲了以特定順序選取子集,只需傳入一個用於指定順序的整數列表或ndarry便可:
In [165]: arr[[4,3,0,6]] Out[165]: array([[4., 4., 4., 4.], [3., 3., 3., 3.], [0., 0., 0., 0.], [6., 6., 6., 6.]])
這段代碼確實達到了咱們的要求!使用負數索引將會從末尾開始選取行:
In [167]: arr[[-3,-5,-7]] Out[167]: array([[5., 5., 5., 5.], [3., 3., 3., 3.], [1., 1., 1., 1.]])
一次傳入多個索引數組會有一點特別。它返回的是一個一維數組,其中的元素對應哥哥索引元組:
In [169]: arr=np.arange(32).reshape((8,4)) In [170]: arr Out[170]: 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 [171]: arr[[1,5,7,2],[0,3,1,2]] Out[171]: array([ 4, 23, 29, 10])
代碼中最終選取的䛾(1,0),(5,3),(7,1)和(2,2)。這些花式索引的行爲可能跟某些用戶的預期不同,選取矩陣的行列子集應該是矩形區域的形式纔對,因而:
In [173]: arr[[1,5,7,2]][:,[0,3,1,2]] Out[173]: array([[ 4, 7, 5, 6], [20, 23, 21, 22], [28, 31, 29, 30], [ 8, 11, 9, 10]])
花式索引跟切片不同,它老是將數據複製到新數組中。
轉置是重塑的一種特殊方式,它返回的是源數據的視圖(不會進行任何複製操做)。數組不只有transpose方法還有一個特殊的T屬性:
In [174]: arr=np.arange(15).reshape(3,5) In [175]: arr Out[175]: array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) In [176]: arr.T Out[176]: array([[ 0, 5, 10], [ 1, 6, 11], [ 2, 7, 12], [ 3, 8, 13], [ 4, 9, 14]])
在進行矩陣計算時,常常須要用到該操做,好比利用np.dot計算矩陣的內積:
In [178]: arr=np.random.randn(6,3) In [179]: np.dot(arr.T,arr) Out[179]: array([[ 4.10149347, 0.88541771, -0.47377443], [ 0.88541771, 5.33214026, -1.6787001 ], [-0.47377443, -1.6787001 , 6.31781659]])
對於高維度數組,transpose須要獲得一個由編號組成的元組才能對這些軸進行轉置:
In [180]: arr=np.arange(16).reshape((2,2,4)) In [181]: arr Out[181]: array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7]], [[ 8, 9, 10, 11], [12, 13, 14, 15]]]) In [182]: arr.transpose((1,0,2)) Out[182]: array([[[ 0, 1, 2, 3], [ 8, 9, 10, 11]], [[ 4, 5, 6, 7], [12, 13, 14, 15]]])
簡單的轉置可使用.T,它其實就是進行軸對換而已。ndarry還有一個swapaxes方法,它須要接受一對軸編號:
In [183]: arr Out[183]: array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7]], [[ 8, 9, 10, 11], [12, 13, 14, 15]]]) In [184]: arr.swapaxes(1,2) Out[184]: array([[[ 0, 4], [ 1, 5], [ 2, 6], [ 3, 7]], [[ 8, 12], [ 9, 13], [10, 14], [11, 15]]])
swapaxes也是返回源數據的視圖(不會進行任何複製操做)。