目錄
- 布爾索引
- 花式索引 (Fancy Indexing)
- 二者的聯(lián)系?
申明:本文中提到的數(shù)組就是特指numpy的數(shù)據(jù)結(jié)構(gòu)ndarray础芍,同理旗闽,一維數(shù)組或者N維數(shù)組,也是指一維活著N維ndarray鲸郊。
參考資料:
(https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#indexing)
Python for Data Analysis 2nd Edition
布爾索引
我們可以通過(guò)一個(gè)布爾數(shù)組來(lái)索引目標(biāo)數(shù)組,以此找出與布爾數(shù)組中值為T(mén)rue的對(duì)應(yīng)的目標(biāo)數(shù)組中的數(shù)據(jù)(后面通過(guò)實(shí)例可清晰的觀察)货邓。需要注意的是秆撮,布爾數(shù)組的長(zhǎng)度必須與目標(biāo)數(shù)組對(duì)應(yīng)的軸的長(zhǎng)度一致。下面通過(guò)幾個(gè)例子來(lái)說(shuō)明换况。
一維數(shù)組的索引
布爾數(shù)組中职辨,下標(biāo)為0,3,4的位置是True,因此將會(huì)取出目標(biāo)數(shù)組中對(duì)應(yīng)位置的元素戈二。
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ù)組中舒裤,下標(biāo)為0,3,4的位置是True,因此將會(huì)取出目標(biāo)數(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]])
我們還可以通過(guò)數(shù)組的邏輯運(yùn)算來(lái)作為索引(實(shí)際上數(shù)組的邏輯運(yùn)算的結(jié)果腾供,也就是一個(gè)布爾數(shù)組)。假設(shè)我們有一個(gè)長(zhǎng)度為7的字符串?dāng)?shù)組,然后對(duì)這個(gè)字符串?dāng)?shù)組進(jìn)行邏輯運(yùn)算台腥,進(jìn)而把元素的結(jié)果(布爾數(shù)組)作為索引的條件傳遞給目標(biāo)數(shù)組(本質(zhì)上,和上面那個(gè)例子是類(lèi)似的)绒北。例如黎侈,還是上面例子中的數(shù)組arr,現(xiàn)在就胡亂想象成每一行數(shù)據(jù)是一個(gè)人的一個(gè)月其中四天賺的錢(qián)闷游。這7行中峻汉,可能有某些行屬于特定的人,那就想象成不同月份賺到的錢(qián)脐往。
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賺的錢(qián)的明細(xì)
In [37]: arr[names == 'Ben']
Out[37]:
array([[ 0, 1, 2, 3],
[ 8, 9, 10, 11],
[24, 25, 26, 27]])
# 在此基礎(chǔ)上休吠,我們還可以添加常規(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]])
上面的例子,通過(guò)邏輯運(yùn)算把屬于Ben的明細(xì)找了出來(lái)业簿。那如果我們想查找不屬于Ben的明細(xì)瘤礁,則可以通過(guò)!=或者~運(yùn)算。這種邏輯運(yùn)算梅尤,還可以用來(lái)做數(shù)據(jù)清洗柜思,后面會(huì)介紹到。
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]])
多個(gè)邏輯運(yùn)算的與和或也是支持的巷燥。例如赡盘,找出Tom或者Jason的明細(xì),并且想對(duì)他們殘忍點(diǎn)缰揪,把他們的錢(qián)都清零陨享。
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]])
除此之外,我們也可以目標(biāo)數(shù)組上做邏輯運(yùn)算钝腺。實(shí)際上抛姑,這種邏輯運(yùn)算的到的結(jié)果是和目標(biāo)數(shù)組維度和長(zhǎng)度都一樣的布爾數(shù)組。例如拍屑,找出arr中大于15的元素途戒,與上面的例子不一樣,這個(gè)例子返回的結(jié)果是一個(gè)一維數(shù)組僵驰。
In [51]: arr[arr>15]
Out[51]: array([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27])
借上面的例子引申一下喷斋,假設(shè)現(xiàn)在想把上述數(shù)組中,小于或者等于15的數(shù)歸零蒜茴,類(lèi)似于數(shù)據(jù)清洗星爪,那么可以通過(guò)下面的方式。
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用來(lái)描述使用整型數(shù)組(這里的數(shù)組粉私,可以是NumPy的數(shù)組顽腾,也可以是python自帶的list)作為索引的術(shù)語(yǔ),其意義是根據(jù)索引數(shù)組的值作為目標(biāo)數(shù)組的某個(gè)軸的下標(biāo)來(lái)取值。對(duì)于使用一維整型數(shù)組作為索引抄肖,如果目標(biāo)是一維數(shù)組久信,那么索引的結(jié)果就是對(duì)應(yīng)位置的元素;如果目標(biāo)是二維數(shù)組漓摩,那么就是對(duì)應(yīng)下標(biāo)的行裙士。
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]])
對(duì)于使用兩個(gè)整型數(shù)組作為索引的時(shí)候,那么結(jié)果是按照順序取出對(duì)應(yīng)軸的對(duì)應(yīng)下標(biāo)的值管毙。特別注意腿椎,這兩個(gè)整型數(shù)組的shape應(yīng)該一致,或者其中一個(gè)數(shù)組應(yīng)該是長(zhǎng)度為1的一維數(shù)組(與NumPy的Broadcasting機(jī)制于關(guān)系)夭咬。例如啃炸,以[1,3,5],[2,4,6]這兩個(gè)整型數(shù)組作為索引,那么對(duì)于二維數(shù)組卓舵,則取出(1,2),(3,4),(5,6)這些坐標(biāo)對(duì)應(yīng)的元素南用。
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)系?
個(gè)人的猜想是边器,布爾索引和花式索引之間训枢,是有聯(lián)系的。竊以為布爾索引是通過(guò)花式索引來(lái)實(shí)現(xiàn)的(雖然不100%確定忘巧,但是我個(gè)人感覺(jué)可以這么理解恒界。各位請(qǐng)自行判斷)。為什么這么說(shuō)砚嘴?先來(lái)看看官方的文檔對(duì)布爾索引的說(shuō)明:
Boolean array indexing
A single boolean index array is practically identical to x[obj.nonzero()]
上面的意思十酣,不就是說(shuō)x[obj]是等價(jià)x[obj.nonzero()](這里obj是一個(gè)布爾數(shù)組)。我們來(lái)驗(yàn)證一下:
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]])
通過(guò)以上例子可知大概的關(guān)系:arr[i] <=> arr[i.nonzero()] => arr[(array([0,2]),)] => arr[array([0,2]),] => arr[[0,2]](到此為止就是花式索引了)际长。在來(lái)看一個(gè)復(fù)雜點(diǎn)的例子:
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])
# 這里不大清楚耸采,為什么結(jié)果是一個(gè)二維數(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])