Numpy的ndarry:一種多維數組對象

Numpy的ndarry:一種多維數組對象

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')

建立ndarry

建立數組的最簡單辦法就是使用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)

ndarry的數據類型

  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 [93]: arr[5:8]=12
 In [94]: arr
 Out[94]: array([ 0,  1,  2,  3,  4, 12, 12, 12,  8,  9])
複製代碼

當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也是返回源數據的視圖(不會進行任何複製操做)。

相關文章
相關標籤/搜索