Python str、list、numpy分區操作

來源:互聯網
上載者:User

Python str、list、numpy分區操作

在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)
>>> 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]])

布爾型索引

假設我們有一個用於儲存資料的數組以及一個儲存姓名的數組(含有重複項)。

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

如果需要選取多個名字組合需要組合多個布爾條件,使用&(和)、|(或)之類的布爾算術運算子即可:

>>> 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))
>>> for i in range(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]])

本文永久更新連結地址:https://www.bkjia.com/Linux/2018-02/151026.htm

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.