list取值_Python中str、list、numpy分片操作
技術標籤:list取值python list中分段python list轉strpython 陣列賦值
在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)將被刪除
>>>dell[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]
拷貝一個分片物件,並修改其中的值,並不會修改原列表物件中的值
#Python學習交流QQ群:778463939
>>>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(mostrecentcalllast):
File"",line1,in
TypeError:canonlyassignaniterable
numpy基本的索引和切片
>>>importnumpyasnp
>>>arr=np.arange(10)
>>>arr
array([0,1,2,3,4,5,6,7,8,9])
>>>arr[5]
5
>>>arr[5:8]
array([5,6,7])
>>>arr[5:8]=12#這裡不會像之前會報錯
>>>arr
array([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_slice
array([12,12,12])
>>>arr_slice[1]=99
>>>arr_slice
array([12,99,12])
>>>arr
array([0,1,2,3,4,12,99,12,8,9])
>>>arr_slice[:]=66
>>>arr
array([0,1,2,3,4,66,66,66,8,9])
>>>arr_slice_copy=arr[5:8].copy()
>>>arr_slice_copy
array([66,66,66])
>>>arr_slice_copy[:]=88
>>>arr_slice_copy
array([88,88,88])
>>>arr
array([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
按照行或者列來進行分片
>>>arr2d
array([[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#同樣,分片表示式的賦值操作也會擴散到源資料
>>>arr2d
array([[1,0,0],
[4,0,0],
[7,0,0]])
布林型索引
假設我們有一個用於儲存資料的陣列以及一個儲存姓名的陣列(含有重複項)。
>>>importnumpyasnp
>>>fromnumpy.randomimportrandint
>>>names=np.array(['Bob','Joe','Bob','Will','Will','Joe','Joe','Bob'])
>>>data=randint(6,size=(8,4))
>>>data
array([[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]])
如果需要選取多個名字組合需要組合多個布林條件,使用&(和)、|(或)之類的布林算術運算子即可:
#Python學習交流QQ群:778463939
>>>mask=(names=='Bob')|(names=='Will')
>>>mask
array([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,我們只需:
>>>data
array([[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
>>>data
array([[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))
>>>foriinrange(8):
...arr[i]=i
...
>>>arr
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.]])
>>>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))
>>>arr
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]])
>>>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])]
>>>arr1
array([[6,5,7,4],
[22,21,23,20],
[30,29,31,28],
[10,9,11,8]])
>>>arr1[1]=66
>>>arr1
array([[6,5,7,4],
[66,66,66,66],
[30,29,31,28],
[10,9,11,8]])
>>>arr
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]])