數(shù)組索引是指使用方括號(hào) ([]) 來(lái)索引數(shù)組值。索引有很多選項(xiàng),這賦予了 NumPy 索引強(qiáng)大的功能,但功能帶來(lái)了一些復(fù)雜性和混亂的可能性。本節(jié)只是對(duì)與索引相關(guān)的各種選項(xiàng)和問(wèn)題的概述。除了單元素索引之外,大多數(shù)這些選項(xiàng)的詳細(xì)信息都可以在相關(guān)部分中找到。
以下大多數(shù)示例顯示了在引用數(shù)組中的數(shù)據(jù)時(shí)索引的使用。這些示例在分配給數(shù)組時(shí)也能正常工作。有關(guān)分配如何工作的具體示例和說(shuō)明,請(qǐng)參閱最后的部分。
一維數(shù)組的單個(gè)元素索引是人們所期望的。它的工作方式與其他標(biāo)準(zhǔn) Python 序列完全一樣。它是基于 0 的,并接受從數(shù)組末尾開(kāi)始索引的負(fù)索引。
>>> x = np.arange(10)
>>> x[2]
2
>>> x[-2]
8
與列表和元組不同,NumPy 數(shù)組支持多維數(shù)組的多維索引。這意味著沒(méi)有必要將每個(gè)維度的索引分隔到它自己的一組方括號(hào)中。
>>> x.shape = (2,5) # now x is 2-dimensional
>>> x[1,3]
8
>>> x[1,-1]
9
請(qǐng)注意,如果索引一個(gè)多維數(shù)組的索引少于維數(shù),則會(huì)得到一個(gè)子維數(shù)組。例如:
>>> x[0]
array([0, 1, 2, 3, 4])
也就是說(shuō),指定的每個(gè)索引都選擇與所選維度的其余部分相對(duì)應(yīng)的數(shù)組。在上面的示例中,選擇 0 意味著長(zhǎng)度為 5 的剩余維度未指定,并且返回的是該維度和大小的數(shù)組。必須注意,返回的數(shù)組不是原始數(shù)組的副本,而是指向與原始數(shù)組相同的內(nèi)存中的值。在這種情況下,返回第一個(gè)位置 (0) 的一維數(shù)組。因此,在返回的數(shù)組上使用單個(gè)索引會(huì)導(dǎo)致返回單個(gè)元素。那是:
>>> x[0][2]
2
所以請(qǐng)注意,盡管第二種情況效率更低,因?yàn)樵诘谝粋€(gè)索引之后創(chuàng)建了一個(gè)新的臨時(shí)數(shù)組,該索引隨后被 2 索引。x[0,2]?=?x[0][2]
請(qǐng)注意那些習(xí)慣于 IDL 或 Fortran 內(nèi)存順序的人,因?yàn)樗c索引有關(guān)。NumPy 使用 C 順序索引。這意味著最后一個(gè)索引通常代表變化最快的內(nèi)存位置,與 Fortran 或 IDL 不同,第一個(gè)索引代表內(nèi)存中變化最快的位置。這種差異代表了很大的混淆可能性。
可以對(duì)數(shù)組進(jìn)行切片和跨步以提取維數(shù)相同但大小與原始數(shù)組不同的數(shù)組。切片和跨步的工作方式與列表和元組的工作方式完全相同,只是它們也可以應(yīng)用于多個(gè)維度。幾個(gè)例子最能說(shuō)明問(wèn)題:
>>> x = np.arange(10)
>>> x[2:5]
array([2, 3, 4])
>>> x[:-7]
array([0, 1, 2])
>>> x[1:7:2]
array([1, 3, 5])
>>> y = np.arange(35).reshape(5,7)
>>> y[1:5:2,::3]
array([[ 7, 10, 13],
[21, 24, 27]])
請(qǐng)注意,數(shù)組切片不會(huì)復(fù)制內(nèi)部數(shù)組數(shù)據(jù),而只會(huì)生成原始數(shù)據(jù)的新視圖。這與列表或元組切片不同,copy()
如果不再需要原始數(shù)據(jù),建議使用顯式切片。
為了從數(shù)組中選擇值列表到新數(shù)組中,可以用其他數(shù)組索引數(shù)組。有兩種不同的方法可以實(shí)現(xiàn)這一點(diǎn)。一種使用一個(gè)或多個(gè)索引值數(shù)組。另一個(gè)涉及提供適當(dāng)形狀的布爾數(shù)組來(lái)指示要選擇的值。索引數(shù)組是一種非常強(qiáng)大的工具,可以避免遍歷數(shù)組中的單個(gè)元素,從而大大提高性能。
可以使用特殊功能通過(guò)索引有效地增加數(shù)組中的維數(shù),以便生成的數(shù)組獲得在表達(dá)式或特定函數(shù)中使用所需的形狀。
NumPy 數(shù)組可以與其他數(shù)組(或任何其他可以轉(zhuǎn)換為數(shù)組的類(lèi)似序列的對(duì)象,例如列表,元組除外;有關(guān)原因,請(qǐng)參閱本文檔末尾)進(jìn)行索引。索引數(shù)組的使用范圍從簡(jiǎn)單、直接的情況到復(fù)雜、難以理解的情況。對(duì)于索引數(shù)組的所有情況,返回的是原始數(shù)據(jù)的副本,而不是切片的視圖。
索引數(shù)組必須是整數(shù)類(lèi)型。數(shù)組中的每個(gè)值指示使用數(shù)組中的哪個(gè)值來(lái)代替索引。為了顯示:
>>> x = np.arange(10,1,-1)
>>> x
array([10, 9, 8, 7, 6, 5, 4, 3, 2])
>>> x[np.array([3, 3, 1, 8])]
array([7, 7, 9, 2])
由值 3、3、1 和 8 組成的索引數(shù)組相應(yīng)地創(chuàng)建了一個(gè)長(zhǎng)度為 4 的數(shù)組(與索引數(shù)組相同),其中每個(gè)索引都被索引數(shù)組在被索引的數(shù)組中具有的值替換。
負(fù)值是允許的,并且可以像處理單個(gè)索引或切片一樣工作:
>>> x[np.array([3,3,-3,8])]
array([7, 7, 4, 2])
索引值越界是錯(cuò)誤的:
>>> x[np.array([3, 3, 20, 8])]
<type 'exceptions.IndexError'>: index 20 out of bounds 0<=index<9
一般而言,使用索引數(shù)組時(shí)返回的是一個(gè)與索引數(shù)組形狀相同的數(shù)組,但被索引的數(shù)組的類(lèi)型和值。例如,我們可以改用多維索引數(shù)組:
>>> x[np.array([[1,1],[2,3]])]
array([[9, 9],
[8, 7]])
當(dāng)多維數(shù)組被索引時(shí),事情變得更加復(fù)雜,尤其是多維索引數(shù)組。這些往往是更不尋常的用途,但它們是允許的,并且它們對(duì)某些問(wèn)題很有用。我們將從最簡(jiǎn)單的多維情況開(kāi)始(使用前面示例中的數(shù)組 y):
>>> y[np.array([0,2,4]), np.array([0,1,2])]
array([ 0, 15, 30])
在這種情況下,如果索引數(shù)組具有匹配的形狀,并且被索引的數(shù)組的每個(gè)維度都有一個(gè)索引數(shù)組,則結(jié)果數(shù)組與索引數(shù)組具有相同的形狀,并且值對(duì)應(yīng)于為每個(gè)維度設(shè)置的索引在索引數(shù)組中的位置。在此示例中,兩個(gè)索引數(shù)組的第一個(gè)索引值都是 0,因此結(jié)果數(shù)組的第一個(gè)值是 y[0,0]。下一個(gè)值是 y[2,1],最后一個(gè)值是 y[4,2]。
如果索引數(shù)組的形狀不同,則會(huì)嘗試將它們廣播為相同的形狀。如果它們不能廣播到相同的形狀,則會(huì)引發(fā)異常:
>>> y[np.array([0,2,4]), np.array([0,1])]
<type 'exceptions.ValueError'>: shape mismatch: objects cannot be
broadcast to a single shape
廣播機(jī)制允許索引數(shù)組與其他索引的標(biāo)量組合。效果是標(biāo)量值用于索引數(shù)組的所有對(duì)應(yīng)值:
>>> y[np.array([0,2,4]), 1]
array([ 1, 15, 29])
跳到下一個(gè)復(fù)雜級(jí)別,可以?xún)H部分索引具有索引數(shù)組的數(shù)組。理解在這種情況下會(huì)發(fā)生什么需要一些思考。例如,如果我們只使用一個(gè)帶有 y 的索引數(shù)組:
>>> y[np.array([0,2,4])]
array([[ 0, 1, 2, 3, 4, 5, 6],
[14, 15, 16, 17, 18, 19, 20],
[28, 29, 30, 31, 32, 33, 34]])
結(jié)果是構(gòu)建一個(gè)新數(shù)組,其中索引數(shù)組的每個(gè)值從被索引的數(shù)組中選擇一行,結(jié)果數(shù)組具有結(jié)果形狀(索引元素的數(shù)量,行的大小)。 這可能有用的一個(gè)例子是顏色查找表,我們希望將圖像的值映射到 RGB 三元組以進(jìn)行顯示。查找表可以有一個(gè)形狀 (nlookup, 3)。用 dtype=np.uint8(或任何整數(shù)類(lèi)型,只要值在查找表的范圍內(nèi))形狀為 (ny, nx) 的圖像索引這樣的數(shù)組將導(dǎo)致形狀為 (ny, nx, 3) 其中三個(gè) RGB 值與每個(gè)像素位置相關(guān)聯(lián)。 通常,結(jié)果數(shù)組的形狀將是索引數(shù)組的形狀(或所有索引數(shù)組被廣播到的形狀)與被索引的數(shù)組中任何未使用的維度(未索引的維度)的形狀的串聯(lián).
用作索引的布爾數(shù)組的處理方式與索引數(shù)組完全不同。布爾數(shù)組的形狀必須與被索引的數(shù)組的初始維度相同。在最直接的情況下,布爾數(shù)組具有相同的形狀:
>>> b = y>20
>>> y[b]
array([21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34])
與整數(shù)索引數(shù)組的情況不同,在布爾情況下,結(jié)果是一個(gè)一維數(shù)組,其中包含索引數(shù)組中與布爾數(shù)組中所有真實(shí)元素相對(duì)應(yīng)的所有元素。索引數(shù)組中的元素總是以行優(yōu)先(C 樣式)順序迭代和返回?。結(jié)果也與 相同?y[np.nonzero(b)]
。與索引數(shù)組一樣,返回的是數(shù)據(jù)的副本,而不是切片時(shí)的視圖。
如果 y 的維度多于 b,結(jié)果將是多維的。例如:
>>> b[:,5] # use a 1-D boolean whose first dim agrees with the first dim of y
array([False, False, False, True, True])
>>> y[b[:,5]]
array([[21, 22, 23, 24, 25, 26, 27],
[28, 29, 30, 31, 32, 33, 34]])
這里從索引數(shù)組中選擇第 4 行和第 5 行并組合成一個(gè)二維數(shù)組。
一般來(lái)說(shuō),當(dāng)布爾數(shù)組的維數(shù)比被索引的數(shù)組少時(shí),這相當(dāng)于 y[b, …],這意味著 y 由 b 索引,后跟盡可能多的 : 以填充 y 的秩。因此,結(jié)果的形狀是一維,包含布爾數(shù)組的 True 元素的數(shù)量,然后是被索引的數(shù)組的其余維度。
例如,使用具有四個(gè) True 元素的形狀 (2,3) 的二維布爾數(shù)組從形狀 (2,3,5) 的 3-D 數(shù)組中選擇行會(huì)導(dǎo)致形狀 (4 ,5):
>>> x = np.arange(30).reshape(2,3,5)
>>> x
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]]])
>>> b = np.array([[True, True, False], [False, True, True]])
>>> x[b]
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]])
有關(guān)更多詳細(xì)信息,請(qǐng)參閱有關(guān)數(shù)組索引的 NumPy 參考文檔。
索引數(shù)組可以與切片組合。例如:
>>> y[np.array([0, 2, 4]), 1:3]
array([[ 1, 2],
[15, 16],
[29, 30]])
實(shí)際上,切片和索引數(shù)組操作是獨(dú)立的。切片操作提取索引為 1 和 2 的列(即第 2 和第 3 列),然后是索引數(shù)組操作提取索引為 0、2 和 4 的行(即第一、第三和第五行)。
這相當(dāng)于:
>>> y[:, 1:3][np.array([0, 2, 4]), :]
array([[ 1, 2],
[15, 16],
[29, 30]])
同樣,切片可以與廣播布爾索引結(jié)合使用:
>>> b = y > 20
>>> b
array([[False, False, False, False, False, False, False],
[False, False, False, False, False, False, False],
[False, False, False, False, False, False, False],
[ True, True, True, True, True, True, True],
[ True, True, True, True, True, True, True]])
>>> y[b[:,5],1:3]
array([[22, 23],
[29, 30]])
為了便于數(shù)組形狀與表達(dá)式和賦值的匹配,可以在數(shù)組索引中使用 np.newaxis 對(duì)象來(lái)添加大小為 1 的新維度。例如:
>>> y.shape
(5, 7)
>>> y[:,np.newaxis,:].shape
(5, 1, 7)
請(qǐng)注意,數(shù)組中沒(méi)有新元素,只是維度增加了。這可以方便地以一種方式組合兩個(gè)數(shù)組,否則將需要顯式重塑操作。例如:
>>> x = np.arange(5)
>>> x[:,np.newaxis] + x[np.newaxis,:]
array([[0, 1, 2, 3, 4],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8]])
省略號(hào)語(yǔ)法可用于指示完全選擇任何剩余的未指定維度。例如:
>>> z = np.arange(81).reshape(3,3,3,3)
>>> z[1,...,2]
array([[29, 32, 35],
[38, 41, 44],
[47, 50, 53]])
這相當(dāng)于:
>>> z[1,:,:,2]
array([[29, 32, 35],
[38, 41, 44],
[47, 50, 53]])
如前所述,可以使用單個(gè)索引、切片以及索引和掩碼數(shù)組來(lái)選擇要分配給的數(shù)組子集。分配給索引數(shù)組的值必須形狀一致(與索引生成的形狀相同或可廣播)。例如,允許為切片分配一個(gè)常量:
>>> x = np.arange(10)
>>> x[2:7] = 1
或正確大小的數(shù)組:
>>> x[2:7] = np.arange(5)
請(qǐng)注意,如果將較高類(lèi)型分配給較低類(lèi)型(如浮點(diǎn)數(shù)為整數(shù))甚至異常(將復(fù)雜數(shù)分配為浮點(diǎn)數(shù)或整數(shù)),則賦值可能會(huì)導(dǎo)致更改:
>>> x[1] = 1.2
>>> x[1]
1
>>> x[1] = 1.2j
TypeError: can't convert complex to int
與某些引用(例如數(shù)組和掩碼索引)不同,總是對(duì)數(shù)組中的原始數(shù)據(jù)進(jìn)行賦值(實(shí)際上,其他任何事情都沒(méi)有意義?。?。但請(qǐng)注意,某些操作可能不會(huì)像人們天真地預(yù)期的那樣起作用。這個(gè)特殊的例子常常讓人們感到驚訝:
>>> x = np.arange(0, 50, 10)
>>> x
array([ 0, 10, 20, 30, 40])
>>> x[np.array([1, 1, 3, 1])] += 1
>>> x
array([ 0, 11, 20, 31, 40])
人們期望第一個(gè)位置會(huì)增加 3。實(shí)際上,它只會(huì)增加 1。原因是因?yàn)閺脑紨?shù)組中提取了一個(gè)新數(shù)組(作為臨時(shí)數(shù)組),其中包含 1、1、3 處的值, 1,然后將值 1 添加到臨時(shí)數(shù)組,然后將臨時(shí)數(shù)組分配回原始數(shù)組。因此,數(shù)組在 x[1]+1 處的值被分配給 x[1] 3 次,而不是增加 3 次。
索引語(yǔ)法非常強(qiáng)大,但在處理可變數(shù)量的索引時(shí)會(huì)受到限制。例如,如果您想編寫(xiě)一個(gè)函數(shù),該函數(shù)可以處理具有各種維數(shù)的參數(shù),而不必為每個(gè)可能的維數(shù)編寫(xiě)特殊的案例代碼,那該怎么做呢?如果向索引提供一個(gè)元組,則該元組將被解釋為索引列表。例如(使用數(shù)組 z 的先前定義):
>>> indices = (1,1,1,1)
>>> z[indices]
40
因此,可以使用代碼構(gòu)造任意數(shù)量索引的元組,然后在索引中使用這些元組。 可以使用 Python 中的 slice() 函數(shù)在程序中指定切片。例如:
>>> indices = (1,1,1,slice(0,2)) # same as [1,1,1,0:2]
>>> z[indices]
array([39, 40])
同樣,可以使用 Ellipsis 對(duì)象通過(guò)代碼指定省略號(hào):
>>> indices = (1, Ellipsis, 1) # same as [1,...,1]
>>> z[indices]
array([[28, 31, 34],
[37, 40, 43],
[46, 49, 52]])
出于這個(gè)原因,可以直接使用 np.nonzero() 函數(shù)的輸出作為索引,因?yàn)樗偸欠祷厮饕龜?shù)組的元組。
由于元組的特殊處理,它們不會(huì)像列表那樣自動(dòng)轉(zhuǎn)換為數(shù)組。舉個(gè)例子:
>>> z[[1,1,1,1]] # produces a large array
array([[[[27, 28, 29],
[30, 31, 32], ...
>>> z[(1,1,1,1)] # returns a single value
40
更多建議: