Numpy的布爾索引與花式索引

目錄

  • 布爾索引
  • 花式索引 (Fancy Indexing)
  • 二者的聯(lián)系?

申明:本文中提到的數(shù)組就是特指numpy的數(shù)據(jù)結構ndarray,同理,一維數(shù)組或者N維數(shù)組,也是指一維活著N維ndarray。

參考資料:
(https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#indexing)
Python for Data Analysis 2nd Edition

布爾索引

我們可以通過一個布爾數(shù)組來索引目標數(shù)組,以此找出與布爾數(shù)組中值為True的對應的目標數(shù)組中的數(shù)據(jù)(后面通過實例可清晰的觀察)。需要注意的是,布爾數(shù)組的長度必須與目標數(shù)組對應的軸的長度一致。下面通過幾個例子來說明。

一維數(shù)組的索引

布爾數(shù)組中,下標為0,3,4的位置是True,因此將會取出目標數(shù)組中對應位置的元素。

In [24]: arr = np.arange(7)

In [25]: booling1 = np.array([True,False,False,True,True,False,False])

In [26]: arr[booling1]
Out[26]: array([0, 3, 4])
二維數(shù)組的索引

布爾數(shù)組中,下標為0,3,4的位置是True,因此將會取出目標數(shù)組中第0,3,4行。

In [27]: arr = np.arange(28).reshape((7,4))

In [28]: arr
Out[28]: 
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]])

In [29]: booling1 = np.array([True,False,False,True,True,False,False])

In [30]: arr[booling1]
Out[30]: 
array([[ 0,  1,  2,  3],
       [12, 13, 14, 15],
       [16, 17, 18, 19]])

我們還可以通過數(shù)組的邏輯運算來作為索引(實際上數(shù)組的邏輯運算的結果,也就是一個布爾數(shù)組)。假設我們有一個長度為7的字符串數(shù)組,然后對這個字符串數(shù)組進行邏輯運算,進而把元素的結果(布爾數(shù)組)作為索引的條件傳遞給目標數(shù)組(本質上,和上面那個例子是類似的)。例如,還是上面例子中的數(shù)組arr,現(xiàn)在就胡亂想象成每一行數(shù)據(jù)是一個人的一個月其中四天賺的錢。這7行中,可能有某些行屬于特定的人,那就想象成不同月份賺到的錢。

In [35]: names = np.array(['Ben','Tom','Ben','Jeremy','Jason','Michael','Ben'])

In [36]: names == 'Ben'
Out[36]: array([ True, False,  True, False, False, False,  True], dtype=bool)

# 找出Ben賺的錢的明細
In [37]: arr[names == 'Ben']
Out[37]: 
array([[ 0,  1,  2,  3],
       [ 8,  9, 10, 11],
       [24, 25, 26, 27]])

# 在此基礎上,我們還可以添加常規(guī)的索引和切片操作
In [38]: arr[names == 'Ben',3]
Out[38]: array([ 3, 11, 27])

In [39]: arr[names == 'Ben',1:4]
Out[39]: 
array([[ 1,  2,  3],
       [ 9, 10, 11],
       [25, 26, 27]])

上面的例子,通過邏輯運算把屬于Ben的明細找了出來。那如果我們想查找不屬于Ben的明細,則可以通過!=或者~運算。這種邏輯運算,還可以用來做數(shù)據(jù)清洗,后面會介紹到。

In [40]: arr[names!='Ben']
Out[40]: 
array([[ 4,  5,  6,  7],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23]])

In [41]: arr[~(names=='Ben')]
Out[41]: 
array([[ 4,  5,  6,  7],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23]])

多個邏輯運算的與和或也是支持的。例如,找出Tom或者Jason的明細,并且想對他們殘忍點,把他們的錢都清零。

In [44]: arr[(names == 'Jason') | (names == 'Tom')]
Out[44]: 
array([[ 4,  5,  6,  7],
       [16, 17, 18, 19]])

In [45]: arr[(names == 'Jason') | (names == 'Tom')] = 0

In [46]: arr
Out[46]: 
array([[ 0,  1,  2,  3],
       [ 0,  0,  0,  0],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [ 0,  0,  0,  0],
       [20, 21, 22, 23],
       [24, 25, 26, 27]])

除此之外,我們也可以目標數(shù)組上做邏輯運算。實際上,這種邏輯運算的到的結果是和目標數(shù)組維度和長度都一樣的布爾數(shù)組。例如,找出arr中大于15的元素,與上面的例子不一樣,這個例子返回的結果是一個一維數(shù)組。

In [51]: arr[arr>15]
Out[51]: array([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27])

借上面的例子引申一下,假設現(xiàn)在想把上述數(shù)組中,小于或者等于15的數(shù)歸零,類似于數(shù)據(jù)清洗,那么可以通過下面的方式。

In [139]: arr
Out[139]: 
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]])

In [140]: arr[arr<=15]=0

In [141]: arr
Out[141]: 
array([[ 0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0],
       [ 0,  0, 16, 17, 18, 19, 20],
       [21, 22, 23, 24, 25, 26, 27]])

花式索引 (Fancy Indexing)

花式索引是NumPy用來描述使用整型數(shù)組(這里的數(shù)組,可以是NumPy的數(shù)組,也可以是python自帶的list)作為索引的術語,其意義是根據(jù)索引數(shù)組的值作為目標數(shù)組的某個軸的下標來取值。對于使用一維整型數(shù)組作為索引,如果目標是一維數(shù)組,那么索引的結果就是對應位置的元素;如果目標是二維數(shù)組,那么就是對應下標的行。

In [69]: arr = np.array(['zero','one','two','three','four'])

In [70]: arr[[1,4]]
Out[70]: 
array(['one', 'four'],
      dtype='<U5')
      

In [71]: arr = np.empty((8,4),dtype=np.int)

In [72]: for i in range(8):
    ...:     arr[i] = i
    ...:     

In [73]: arr
Out[73]: 
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]])
In [75]: arr[[4,3,0,6]]
Out[75]: 
array([[4, 4, 4, 4],
       [3, 3, 3, 3],
       [0, 0, 0, 0],
       [6, 6, 6, 6]])

In [76]: arr[[-3,-5,-7]]
Out[76]: 
array([[5, 5, 5, 5],
       [3, 3, 3, 3],
       [1, 1, 1, 1]])

對于使用兩個整型數(shù)組作為索引的時候,那么結果是按照順序取出對應軸的對應下標的值。特別注意,這兩個整型數(shù)組的shape應該一致,或者其中一個數(shù)組應該是長度為1的一維數(shù)組(與NumPy的Broadcasting機制于關系)。例如,以[1,3,5],[2,4,6]這兩個整型數(shù)組作為索引,那么對于二維數(shù)組,則取出(1,2),(3,4),(5,6)這些坐標對應的元素。

In [77]: arr = np.arange(42).reshape(6,7)

In [78]: arr
Out[78]: 
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, 32, 33, 34],
       [35, 36, 37, 38, 39, 40, 41]])

In [79]: arr[[1,3,5],[2,4,6]]
Out[79]: array([ 9, 25, 41])

二者的聯(lián)系?

個人的猜想是,布爾索引和花式索引之間,是有聯(lián)系的。竊以為布爾索引是通過花式索引來實現(xiàn)的(雖然不100%確定,但是我個人感覺可以這么理解。各位請自行判斷)。為什么這么說?先來看看官方的文檔對布爾索引的說明:

Boolean array indexing
A single boolean index array is practically identical to x[obj.nonzero()]

上面的意思,不就是說x[obj]是等價x[obj.nonzero()](這里obj是一個布爾數(shù)組)。我們來驗證一下:

In [112]: arr = np.arange(12).reshape(3,4)

In [113]: i = np.array([True,False,True])

In [114]: i.nonzero()
Out[114]: (array([0, 2]),)

In [115]: arr[i]
Out[115]: 
array([[ 0,  1,  2,  3],
       [ 8,  9, 10, 11]])

In [116]: arr[i.nonzero()]
Out[116]: 
array([[ 0,  1,  2,  3],
       [ 8,  9, 10, 11]])

通過以上例子可知大概的關系:arr[i] <=> arr[i.nonzero()] => arr[(array([0,2]),)] => arr[array([0,2]),] => arr[[0,2]](到此為止就是花式索引了)。在來看一個復雜點的例子:

In [131]: i
Out[131]: array([ True, False,  True], dtype=bool)

In [132]: j
Out[132]: array([ True,  True, False, False], dtype=bool)

In [133]: i.nonzero()
Out[133]: (array([0, 2]),)

In [134]: j.nonzero()
Out[134]: (array([0, 1]),)

In [135]: arr[i,j]
Out[135]: array([0, 9])

# 這里不大清楚,為什么結果是一個二維數(shù)組
In [136]: arr[i.nonzero(),j.nonzero()]
Out[136]: array([[0, 9]])

In [137]: arr[[0,2],[0,1]]
Out[137]: array([0, 9])
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容