2017-10-06 70 views
2

我遇到了一些在我看來像在Numpy切片中不一致的行爲。具體地,請考慮下面的例子:在numpy數組中看似不一致的切片行爲

import numpy as np 
a = np.arange(9).reshape(3,3) # a 2d numpy array 
y = np.array([1,2,2])   # vector that will be used to index the array 

b = a[np.arange(len(a)),y]  # a vector (what I want) 
c = a[:,y]      # a matrix ?? 

我想獲得載體中,使得第i個元素是a[i,y[i]]。我嘗試了兩件事(上面的bc),並且很驚訝bc不一樣......實際上一個是矢量,另一個是矩陣!我的印象是,:是「所有元素」的縮寫,但顯然它的含義更加微妙。

試錯後,我現在有點(b == np.diag(c))理解上的差異,但希望在爲什麼它們是不同的,究竟採用:意味着,以及如何瞭解什麼時候使用這兩種情況下澄清。

謝謝!

+0

爲什麼你認爲這是不一致的? –

+0

不一致,因爲在我以前使用Python時,我被訓練認爲':'是指「所有元素」。當我索引數組時,我期望'myArr [:]'和'myArr [np.arrage(len(myArr))]'產生相同的結果。它確實如此,所以當我沒有把它推廣到幾個維度時,我感到很驚訝。 – Charles

+0

@BradSolomon我知道他們會產生同樣的結果,這就是爲什麼我期望':'與'np.arange(len(a))':)意思相同。它在一維中執行,但不是在兩個或兩個以上 – Charles

回答

0

當您通過

np.arange(len(a)), y 

您可以查看結果爲所有的索引你通過壓縮元素。在這種情況下,索引由np.arange(len(a))y

np.arange(len(a)) 
# [0, 1, 2] 
y 
# [1, 2, 2] 

實際上取要素:(0,1),(1,2),和(2,2)。

print(a[0, 1], a[1, 2], a[2, 2]) # 0th, 1st, 2nd elements from each indexer 
# 1 5 8 

在第二種情況下,沿第一個維度取整個切片。 (冒號前沒有)。所以這是沿着第0軸的所有元素。然後用y指定要沿每一行的第1,第2和第2個元素。 (0索引。)

如你指出的那樣,它可能看起來有點不直觀的,結果給出了切片的各個元件是等價的是不同的:

a[:] == a[np.arange(len(a))] 

a[:y] == a[:y] 

但是,NumPy advanced indexing關心什麼類型您索引(元組,整數等)時傳遞的數據結構。事情會變得非常快速。

背後的細節是這樣的:首先考慮所有 NumPy的索引是一般形式x[obj],其中obj是不管你傳遞的評價。 NumPy的如何「表現」取決於什麼類型的對象obj的是:

高級索引時觸發選擇對象obj是 非元組序列對象,ndarray(數據類型爲整型或布爾) , 或具有至少一個序列對象或ndarray(數據類型爲 integer或bool)的元組。 ... 的高級索引定義意味着x [(1,2,3),]是 大於x [(1,2,3)]根本不同的。後者等同於 X [1,2,3]將觸發基本選擇而前者將 觸發高級索引。一定要明白爲什麼會發生這種情況。

在您的第一個案例中,obj = np.arange(len(a)),y,這是一個符合上述粗體法案的元組。這會觸發高級索引並強制執行上述行爲。

至於第二種情況下,[:,y]

當存在至少一個片(:),省略號(...)或在 np.newaxis的索引(或陣列具有比多個尺寸有先進的 索引),那麼行爲可能會更復雜。 它像 串接索引結果針對每個高級索引元素。

證明:

# Concatenate the indexing result for each advanced index element. 
np.vstack((a[0, y], a[1, y], a[2, y])) 
2

這是很難理解的高級索引(使用列表或數組)不理解廣播。

In [487]: a=np.arange(9).reshape(3,3) 
In [488]: idx = np.array([1,2,2]) 

指數用(3)和(3)產生的形狀(3)結果:

In [489]: a[np.arange(3),idx] 
Out[489]: array([1, 5, 8]) 

與(3,1)和(3,)索引,結果是( 3,3)

In [490]: a[np.arange(3)[:,None],idx] 
Out[490]: 
array([[1, 2, 2], 
     [4, 5, 5], 
     [7, 8, 8]]) 

切片:做基本相同的事情。有細微的差別,但這裏是一樣的。

In [491]: a[:,idx] 
Out[491]: 
array([[1, 2, 2], 
     [4, 5, 5], 
     [7, 8, 8]]) 

ix_做同樣的事情,轉換(3)&(3)到(3,1)和(1,3):

In [492]: np.ix_(np.arange(3),idx) 
Out[492]: 
(array([[0], 
     [1], 
     [2]]), array([[1, 2, 2]])) 

廣播的總和可能會幫助可視化這兩種情況:

In [495]: np.arange(3)*10+idx 
Out[495]: array([ 1, 12, 22]) 
In [496]: np.sum(np.ix_(np.arange(3)*10,idx),axis=0) 
Out[496]: 
array([[ 1, 2, 2], 
     [11, 12, 12], 
     [21, 22, 22]])