NumPy索引

數(shù)組索引是指使用方括號([])來索引數(shù)組值。索引有很多選項,它可以為numpy索引提供強大的功能,但是功能會帶來一些復雜性和混淆的可能性。本節(jié)僅概述了與索引相關的各種選項和問題。除了單個元素索引之外,大多數(shù)這些選項的詳細信息都可以在相關章節(jié)中找到。

賦值與引用

以下大多數(shù)示例體現(xiàn)在引用數(shù)組中的數(shù)據(jù)時使用索引。分配給數(shù)組時,這些示例也可以正常運行的。有關分配的原理具體示例和說明,請參見最后一節(jié)。

單個元素索引

人們期望的是1-D數(shù)組的單元素索引。它的工作方式與其他標準Python序列完全相同。它基于0,并接受從數(shù)組末尾開始索引的負索引。

>>> x = np.arange(10)
>>> x[2]
2
>>> x[-2]
8

與列表和元組不同,numpy數(shù)組支持多維數(shù)組的多維索引。這意味著沒有必要將每個維度的索引分成它自己的一組方括號。

>>> x.shape = (2,5) # now x is 2-dimensional
>>> x[1,3]
8
>>> x[1,-1]
9

請注意,如果索引索引比維度少的多維數(shù)組,則會獲得一個子維數(shù)組。例如:

>>> x[0]
array([0, 1, 2, 3, 4])

也就是說,指定的每個索引選擇與所選維度的其余部分對應的數(shù)組。在上面的示例中,選擇0表示長度為5的剩余維度未指定,返回的是該維度和大小的數(shù)組。必須注意的是,返回的數(shù)組不是原始數(shù)據(jù)的副本,而是指向內存中與原始數(shù)組相同的值。在這種情況下,返回第一個位置(0)的1-D數(shù)組。因此,在返回的數(shù)組上使用單個索引會導致返回單個元素。那是:

>>> x[0][2]
2

請注意,盡管第二種情況效率較低,因為在第一個索引之后創(chuàng)建了一個新的臨時數(shù)組,該索引隨后被索引為2:x[0,2] = x[0][2]

請注意那些習慣于IDL或Fortran內存順序的內容,因為它與索引有關。NumPy使用C順序索引。這意味著最后一個索引通常代表最快速變化的內存位置,與Fortran或IDL不同,其中第一個索引代表內存中變化最快的位置。這種差異代表了混淆的巨大潛力。

其他索引選項

可以對數(shù)組進行切片和跨步以提取具有相同數(shù)量的尺寸但具有與原始尺寸不同的尺寸的數(shù)組。切片和跨步的工作方式與列表和元組的工作方式完全相同,只是它們也可以應用于多個維度。一些例子說明了最好的:

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

請注意,數(shù)組切片不會復制內部數(shù)組數(shù)據(jù),只會生成原始數(shù)據(jù)的新視圖。這與列表或元組切片不同,copy()如果不再需要原始數(shù)據(jù),建議使用顯式。

可以使用其他數(shù)組索引數(shù)組,以便從數(shù)組中選擇值列表到新數(shù)組中。有兩種不同的方法來實現(xiàn)這一點。一個使用一個或多個索引值數(shù)組。另一個涉及給出一個正確形狀的布爾數(shù)組來指示要選擇的值。索引數(shù)組是一個非常強大的工具,可以避免循環(huán)遍歷數(shù)組中的各個元素,從而大大提高性能。

可以使用特殊功能通過索引有效地增加數(shù)組中的維數(shù),以便生成的數(shù)組獲取在表達式或特定函數(shù)中使用所需的形狀。

索引數(shù)組

NumPy數(shù)組可以使用其他數(shù)組(或任何其他可以轉換為數(shù)組的類似序列的對象,如列表,除元組之外的索引;請參閱本文檔末尾的原因)。索引數(shù)組的使用范圍從簡單,直接的案例到復雜的,難以理解的案例。對于索引數(shù)組的所有情況,返回的是原始數(shù)據(jù)的副本,而不是切片獲取的視圖。

索引數(shù)組必須是整數(shù)類型。數(shù)組中的每個值指示要使用的數(shù)組中的哪個值代替索引。為了顯示:

>>> 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ù)組相應地創(chuàng)建一個長度為4的數(shù)組(與索引數(shù)組相同),其中每個索引由索引數(shù)組在被索引的數(shù)組中具有的值替換。

允許使用負值,并且與單個索引或切片一樣工作:

>>> x[np.array([3,3,-3,8])]
array([7, 7, 4, 2])

索引值超出范圍是錯誤的:

>>> x[np.array([3, 3, 20, 8])]
<type 'exceptions.IndexError'>: index 20 out of bounds 0<=index<9

一般來說,使用索引數(shù)組時返回的是與索引數(shù)組具有相同形狀的數(shù)組,但索引的數(shù)組的類型和值。作為示例,我們可以使用多維索引數(shù)組:

>>> x[np.array([[1,1],[2,3]])]
array([[9, 9],
       [8, 7]])

索引多維數(shù)組

當索引多維數(shù)組時,事情變得更加復雜,特別是對于多維索引數(shù)組。這些往往是更不尋常的用途,但它們是允許的,它們對某些問題很有用。我們將從最簡單的多維情況開始(使用前面示例中的數(shù)組y):

>>> y[np.array([0,2,4]), np.array([0,1,2])]
array([ 0, 15, 30])

在這種情況下,如果索引數(shù)組具有匹配的形狀,并且索引數(shù)組的每個維度都有一個索引數(shù)組,則結果數(shù)組具有與索引數(shù)組相同的形狀,并且值對應于每個索引的索引集在索引數(shù)組中的位置。在此示例中,兩個索引數(shù)組的第一個索引值均為0,因此結果數(shù)組的第一個值為y [0,0]。下一個值是y [2,1],最后一個是y [4,2]。

如果索引數(shù)組的形狀不同,則嘗試將它們廣播為相同的形狀。如果它們無法廣播到相同的形狀,則會引發(fā)異常:

>>> y[np.array([0,2,4]), np.array([0,1])]
<type 'exceptions.ValueError'>: shape mismatch: objects cannot be
broadcast to a single shape

廣播機制允許索引數(shù)組與其他索引的標量組合。結果是標量值用于索引數(shù)組的所有相應值:

>>> y[np.array([0,2,4]), 1]
array([ 1, 15, 29])

跳到下一級復雜性,可以僅使用索引數(shù)組對數(shù)組進行部分索引。需要一些思考才能理解在這種情況下會發(fā)生什么。例如,如果我們只使用一個帶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]])

結果是構造一個新數(shù)組,其中索引數(shù)組的每個值從被索引的數(shù)組中選擇一行,結果數(shù)組具有結果形狀(索引元素的數(shù)量,行的大?。?。

這可能有用的示例是用于顏色查找表,其中我們想要將圖像的值映射到RGB三元組以供顯示。查找表可以具有形狀(nlookup,3)。使用帶有dtype = np.uint8的形狀(ny,nx)的圖像索引此類數(shù)組(或任何整數(shù)類型,只要值與查找表的邊界一致)將導致形狀數(shù)組(ny,nx, 3)其中三個RGB值與每個像素位置相關聯(lián)。

通常,結果數(shù)組的形狀將是索引數(shù)組的形狀(或所有索引數(shù)組被廣播的形狀)與被索引的數(shù)組中任何未使用的維度(未索引的那些)的形狀的串聯(lián)。

布爾或“掩碼”索引數(shù)組






用作索引的布爾數(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ù)組的情況不同,在布爾情況下,結果是一個一維數(shù)組,其中包含索引數(shù)組中與布爾數(shù)組中所有真實元素對應的所有元素。索引數(shù)組中的元素始終是迭代的,并以
行主

(C樣式)順序返回。結果也是一樣的
y[np.nonzero(b)]。與索引數(shù)組一樣,返回的是數(shù)據(jù)的副本,而不是切片所獲得的視圖。

如果y的維數(shù)多于b,則結果將是多維的。例如:

>>> 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行,并組合成2-D數(shù)組。

通常,當布爾數(shù)組的維數(shù)小于被索引的數(shù)組時,這相當于y [b,...],這意味著y被b索引后跟多少:填充y的等級所需的數(shù)量。因此,結果的形狀是一個維度,其中包含布爾數(shù)組的True元素的數(shù)量,后跟被索引的數(shù)組的其余維度。

例如,使用具有四個True元素的形狀(2,3)的二維布爾數(shù)組來從三維形狀數(shù)組(2,3,5)中選擇行,從而得到形狀的二維結果(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]])

有關更多詳細信息,請參閱有關數(shù)組索引的numpy參考文檔。

將索引數(shù)組與切片組合

索引數(shù)組可以與切片組合。例如:

>>> y[np.array([0,2,4]),1:3]
array([[ 1,  2],
       [15, 16],
       [29, 30]])

實際上,切片被轉換為索引數(shù)組 np.array([[1,2]]) (shape (1,2)),它與索引數(shù)組一起廣播以產(chǎn)生一個結果 shape(3,2) 的數(shù)組。

同樣,切片可以與廣播的布爾索引組合:

>>> 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ù)組形狀與表達式和賦值的輕松匹配,可以在數(shù)組索引中使用np.newaxis對象來添加大小為1的新維度。例如:

>>> y.shape
(5, 7)
>>> y[:,np.newaxis,:].shape
(5, 1, 7)

請注意,數(shù)組中沒有新元素,只是增加了維度。這可以方便地以一種方式組合兩個數(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]])

省略號語法可用于指示完全選擇任何剩余的未指定維度。例如:

>>> z = np.arange(81).reshape(3,3,3,3)
>>> z[1,...,2]
array([[29, 32, 35],
       [38, 41, 44],
       [47, 50, 53]])

這相當于:

>>> z[1,:,:,2]
array([[29, 32, 35],
       [38, 41, 44],
       [47, 50, 53]])

為索引數(shù)組賦值

如上所述,可以選擇要分配給使用單個索引,切片,索引和掩碼數(shù)組的數(shù)組的子集。分配給索引數(shù)組的值必須是形狀一致的(與索引生成的形狀相同的形狀或可廣播)。例如,允許為切片分配常量:

>>> x = np.arange(10)
>>> x[2:7] = 1

或者正確大小的數(shù)組:

>>> x[2:7] = np.arange(5)

請注意,如果將較高類型分配給較低類型(如浮點數(shù)到整數(shù))或甚至異常(將復數(shù)分配給浮點數(shù)或整數(shù)),則賦值可能會導致更改:

>>> x[1] = 1.2
>>> x[1]
1
>>> x[1] = 1.2j
<type 'exceptions.TypeError'>: can't convert complex to long; use
long(abs(z))

與某些引用(例如數(shù)組和掩碼索引)不同,總是對數(shù)組中的原始數(shù)據(jù)進行賦值(實際上,其他任何內容都沒有意義?。?。但請注意,某些操作可能無法正常工作。這個特殊的例子通常讓人驚訝:

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

人們期望第一個位置將增加3.實際上,它只會增加1.原因是因為從原始(作為臨時)提取的新數(shù)組包含值1,1,3 ,1,然后將值1添加到臨時值,然后將臨時值分配回原始數(shù)組。因此,x [1] +1處的數(shù)組的值被賦予x [1]三次,而不是遞增3次。

在程序中處理可變數(shù)量的索引

索引語法非常強大,但在處理可變數(shù)量的索引時會受到限制。例如,如果要編寫一個可以處理具有不同維數(shù)的參數(shù)的函數(shù),而不必為每個可能的維度編寫特殊的案例代碼,那么該怎么做呢?如果向索引提供元組,則元組將被解釋為索引列表。例如(使用先前的數(shù)組z定義):

>>> indices = (1,1,1,1)
>>> z[indices]
40

因此,可以使用代碼構造任意數(shù)量的索引的元組,然后在索引中使用它們。

可以使用Python中的slice() 函數(shù)在程序中指定切片。例如:

>>> indices = (1,1,1,slice(0,2)) # same as [1,1,1,0:2]
>>> z[indices]
array([39, 40])

同樣,可以使用Ellipsis對象通過代碼指定省略號:

>>> indices = (1, Ellipsis, 1) # same as [1,...,1]
>>> z[indices]
array([[28, 31, 34],
       [37, 40, 43],
       [46, 49, 52]])

由于這個原因,可以直接使用 np.nonzero() 函數(shù)的輸出作為索引,因為它總是返回索引數(shù)組的元組。

因為對元組的特殊處理,它們不會像列表那樣自動轉換為數(shù)組。舉個例子:

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

作者:柯廣的網(wǎng)絡日志 ? NumPy索引


微信公眾號:Java大數(shù)據(jù)與數(shù)據(jù)倉庫