標籤:last 獲得 二維數組 間隔 sha 擷取 mask from 重複
在Python裡,像字串(str)、列表(list)、元組(tupple)和這類序列類型都支援切片操作
對對象切片,s是一個字串,可以通過類似數組索引的方式擷取字串中的字元,同時也可以用s[a:b:c]的形式對s在a和b之間,以c為間隔取值,c的值還可以為負,負值則意味著反向取值
>>> s = ‘bicycle‘>>> s[0]‘b‘>>> s[1]‘i‘>>> s[::3]‘bye‘>>> s[::-1]‘elcycib‘>>> s[::-2]‘eccb‘
給切片賦值
首先,產生一個長度為16,從0到15的列表
>>> l = list(range(16))>>> l[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
用[20,30]將取代索引[2,5)的值
>>> l[2:5] = [20, 30] >>> l[0, 1, 20, 30, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
索引[5,8)將被刪除
>>> del l[5:8]>>> l[0, 1, 20, 30, 5, 9, 10, 11, 12, 13, 14, 15]
從數組第9個索引開始,以兩個單位為間隔,將[11,22]賦值給左邊的分區對象,如果賦值數組中元素的個數和分區對象中元素的個數不同,則會報錯
>>> l[9::2] [13, 15]>>> l[9::2] = [11, 22] >>> l[0, 1, 20, 30, 5, 9, 10, 11, 12, 11, 14, 22]>>> l[6::2][10, 12, 14]>>> l[6::2] = [66, 77, 88] # 同理,l[6::2]必須為[n1,n2,n3]的數組,如果不是則將其 賦值為[66, 77, 88]則會報錯>>> l[0, 1, 20, 30, 5, 9, 66, 11, 77, 11, 88, 22]
列表l[2:5]的結果是[20, 30, 5],而我們的賦值是[30, 33],所以30會代替20,33會代替30,而5則會被去除。如果左邊數組元素的個數少於賦值數組中元素的個數,則原數組分區之後的元素會排在新元素之後
>>> l[2:5][20, 30, 5]>>> l[2:5] = [30, 33] >>> l[0, 1, 30, 33, 9, 66, 11, 77, 11, 88, 22]>>> l[2:5][30, 33, 9]>>> l[2:5] = [-10, -20, -30, -40, -50] >>> l[0, 1, -10, -20, -30, -40, -50, 66, 11, 77, 11, 88, 22]
拷貝一個分區對象,並修改其中的值,並不會修改原列表對象中的值
>>> l1 = l[2:5]>>> l1[-10, -20, -30]>>> l1 = [10, 20, 30]>>> l1[10, 20, 30]>>> l[0, 1, -10, -20, -30, -40, -50, 66, 11, 77, 11, 88, 22]
如果將一個數字賦值給左邊的分區對象,則會報錯
>>> l[2:5] = 10 Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: can only assign an iterable
numpy基本的索引和切片
>>> import numpy as np>>> arr = np.arange(10)>>> arrarray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])>>> arr[5]5>>> arr[5:8]array([5, 6, 7])>>> arr[5:8] = 12 # 這裡不會像之前會報錯>>> arrarray([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
如上所示,當你將一個標量賦值給一個切片對象時(如arr[5:8] = 12),該值會自動傳播到整個選區。跟之前列表的分區的區別在於,numpy數組分區是原始數組的視圖,資料沒有被複製,視圖上任何的修改都會直接反映到來源資料上,如果不希望修改到來源資料,則用arr[5:8].copy():
>>> arr_slice = arr[5:8]>>> arr_slicearray([12, 12, 12])>>> arr_slice[1] = 99>>> arr_slicearray([12, 99, 12])>>> arrarray([ 0, 1, 2, 3, 4, 12, 99, 12, 8, 9])>>> arr_slice[:] = 66>>> arrarray([ 0, 1, 2, 3, 4, 66, 66, 66, 8, 9])>>> arr_slice_copy = arr[5:8].copy()>>> arr_slice_copyarray([66, 66, 66])>>> arr_slice_copy[:] = 88>>> arr_slice_copyarray([88, 88, 88])>>> arrarray([ 0, 1, 2, 3, 4, 66, 66, 66, 8, 9])
在一個二維數組中,各索引位置上的元素不再是標量而是一維數組:
>>> arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])>>> arr2d[2]array([7, 8, 9])>>> arr2d[0][2]3>>> arr2d[0, 2]3
按照行或者列來進行分區
>>> arr2darray([[1, 2, 3], [4, 5, 6], [7, 8, 9]])>>> arr2d[:2] # 取前兩行,即第0行和第1行array([[1, 2, 3], [4, 5, 6]])>>> arr2d[:2, 1:] # 取前兩行的第零列之後所有元素array([[2, 3], [5, 6]])>>> arr2d[:, 1:2] # 取所有行的第一列元素(列索引從0開始)array([[2], [5], [8]])>>> arr2d[1, :2] # 取第一行的前兩列的元素元素array([4, 5])>>> arr2d[2, :1] # 取第二行的第零列元素array([7])>>> arr2d[:, :1] # 取所有行的第零列元素array([[1], [4], [7]])>>> arr2d[:, 1:] = 0 # 同樣,分區運算式的賦值操作也會擴散到來源資料>>> arr2darray([[1, 0, 0], [4, 0, 0], [7, 0, 0]])
布爾型索引
假設我們有一個用於儲存資料的數組以及一個儲存姓名的數組(含有重複項)。
>>> import numpy as np>>> from numpy.random import randint>>> names = np.array([‘Bob‘, ‘Joe‘, ‘Bob‘, ‘Will‘, ‘Will‘, ‘Joe‘, ‘Joe‘, ‘Bob‘])>>> data = randint(6, size=(8, 4))>>> dataarray([[2, 1, 2, 2], [3, 3, 4, 2], [0, 5, 3, 5], [2, 1, 5, 2], [1, 3, 0, 3], [0, 0, 0, 1], [0, 0, 0, 5], [4, 2, 5, 1]])
假設每個名字都對應data數組中的一行,而我們想要選出對應於名字“Bob”的所有行。我們可以這樣操作
>>> names == ‘Bob‘array([ True, False, True, False, False, False, False, True], dtype=bool)>>> data[names == ‘Bob‘]array([[2, 1, 2, 2], [0, 5, 3, 5], [4, 2, 5, 1]])
布爾型數組的長度必須跟被索引的數組長度一致,此外,還可以將布爾型數組跟分區、整數(或整數序列)混合使用
>>> data[names == ‘Bob‘, 2:]array([[2, 2], [3, 5], [5, 1]])>>> data[names == ‘Bob‘, 3]array([2, 5, 1])>>> data[names == ‘Bob‘, 3:]array([[2], [5], [1]])
如果需要選取多個名字組合需要組合多個布爾條件,使用&(和)、|(或)之類的布爾算術運算子即可:
>>> mask = (names == ‘Bob‘) | (names == ‘Will‘)>>> maskarray([ True, False, True, True, True, False, False, True], dtype=bool)>>> data[mask]array([[2, 1, 2, 2], [0, 5, 3, 5], [2, 1, 5, 2], [1, 3, 0, 3], [4, 2, 5, 1]])
注意:Python關鍵字and和or在布爾型資料中無效
通過布爾型數組設定值是一種經常用到的手段,為了將data中所有的偶數設定為3,我們只需:
>>> dataarray([[2, 1, 2, 2], [3, 3, 4, 2], [0, 5, 3, 5], [2, 1, 5, 2], [1, 3, 0, 3], [0, 0, 0, 1], [0, 0, 0, 5], [4, 2, 5, 1]])>>> data[data % 2 == 0] = 3>>> dataarray([[3, 1, 3, 3], [3, 3, 3, 3], [3, 5, 3, 5], [3, 1, 5, 3], [1, 3, 3, 3], [3, 3, 3, 1], [3, 3, 3, 5], [3, 3, 5, 1]])
花式索引
花式索引是numpy術語,它指的是利用整數數組進行索引。假設我們有一個8×4數組:
>>> arr = np.empty((8, 4))>>> for i in range(8):... arr[i] = i...>>> arrarray([[ 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.]])>>> arr[[3, 5, 0, 6]]array([[ 3., 3., 3., 3.], [ 5., 5., 5., 5.], [ 0., 0., 0., 0.], [ 6., 6., 6., 6.]])>>> arr[[3, -3, -1]]array([[ 3., 3., 3., 3.], [ 5., 5., 5., 5.], [ 7., 7., 7., 7.]])
arr[[3, 5, 0, 6]]會索引源數組的第三行、第五行、第零行、第六行,然後組成新的視圖返回,而arr[[3, -3, -1]]則會索引第三行、倒數第三行和倒數第一行
我們產生了一個8×4數組,然後傳入兩個索引數組[1, 5, 7, 2]、 [0, 3, 1, 2],然後我們得到一個一維的數組
>>> arr = np.arange(32).reshape((8, 4))>>> arrarray([[ 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]])>>> arr[[1, 5, 7, 2], [0, 3, 1, 2]]array([ 4, 23, 29, 10])
下面我們分析一下上面的代碼究竟發生了什麼,第一個索引數組[1, 5, 7, 2],我們擷取第一行、第五行、第七行和第二行,然後我們將根據第二個索引數組 [0, 3, 1, 2],擷取第一行的第零列、第五行的三列……以此類推,最後,我們獲得了一個一維的數組
當然,在有些情況下,我們希望按照不同的順序擷取源數組不同的行,並且還要在擷取後,改動原來的列順序,於是我們可以這樣做:
>>> arr[[1, 5, 7, 2]]array([[ 4, 5, 6, 7], [20, 21, 22, 23], [28, 29, 30, 31], [ 8, 9, 10, 11]])>>> arr[[1, 5, 7, 2]][:, [2, 1, 3, 0]]array([[ 6, 5, 7, 4], [22, 21, 23, 20], [30, 29, 31, 28], [10, 9, 11, 8]])>>> arr[np.ix_([1, 5, 7, 2], [2, 1, 3, 0])]array([[ 6, 5, 7, 4], [22, 21, 23, 20], [30, 29, 31, 28], [10, 9, 11, 8]])
如上,我們既可以用arr[[1, 5, 7, 2]][:, [2, 1, 3, 0]]這樣的方式擷取擷取不同的行,再改變其中的列順序,同時也可以用np.ix_函數達到一樣的目的,不過需要注意的一點是,花式索引跟分區不一樣,它總是將資料複製到新的數組中:
>>> arr1 = arr[np.ix_([1, 5, 7, 2], [2, 1, 3, 0])]>>> arr1array([[ 6, 5, 7, 4], [22, 21, 23, 20], [30, 29, 31, 28], [10, 9, 11, 8]])>>> arr1[1] = 66>>> arr1array([[ 6, 5, 7, 4], [66, 66, 66, 66], [30, 29, 31, 28], [10, 9, 11, 8]])>>> arrarray([[ 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]])
Python str、list、numpy分區操作