2012-06-06 238 views
11

如果這是冗餘或超級基礎,請原諒我。我來自R的Python/Numpy,很難在腦海中翻轉。Numpy:通過多維數組對多維數組排序

我有一個n維數組,我想使用另一個n維索引值數組進行排序。我知道我可以把它放在一個循環中,但似乎應該有一個非常簡潔的Numpyonic方式來將它擊敗。這是我的示例代碼來設置,其中n = 2的問題:

a1 = random.standard_normal(size=[2,5]) 
index = array([[0,1,2,4,3] , [0,1,2,3,4] ]) 

所以現在我有一個2×5陣列的隨機數和一個2×5索引。我已經讀了take()的幫助,現在大概有10次,但我的大腦顯然沒有提供幫助。

我想這可能讓我有:

take(a1, index) 

array([[ 0.29589188, -0.71279375, -0.18154864, -1.12184984, 0.25698875], 
     [ 0.29589188, -0.71279375, -0.18154864, 0.25698875, -1.12184984]]) 

但是這顯然只是重新排序的第一個元素(我猜是因爲扁平化)。

有關我如何從我的位置獲取解決方案的任何提示,該解決方案通過index ...元素n的元素0對a1的元素0進行排序?

+0

所以,如果我理解正確,你想重新排序'索引'的每一行索引'a1'的每個「行」?換句話說,如果你是1D,a1.take(索引),但是對於每一行都這樣做? –

+0

是。因此,通過第一行索引排序a1的第一行,並通過索引的第二行排列a1的第二行。當a1增長到n維時,那麼指數也是如此。 –

回答

11

我想不出如何在N維工作這還,但 這裏是2D版本:

>>> a = np.random.standard_normal(size=(2,5)) 
>>> a 
array([[ 0.72322499, -0.05376714, -0.28316358, 1.43025844, -0.90814293], 
     [ 0.7459107 , 0.43020728, 0.05411805, -0.32813465, 2.38829386]]) 
>>> i = np.array([[0,1,2,4,3],[0,1,2,3,4]]) 
>>> a[np.arange(a.shape[0])[:,np.newaxis],i] 
array([[ 0.72322499, -0.05376714, -0.28316358, -0.90814293, 1.43025844], 
     [ 0.7459107 , 0.43020728, 0.05411805, -0.32813465, 2.38829386]]) 

這裏是N維版本:

>>> a[list(np.ogrid[[slice(x) for x in a.shape]][:-1])+[i]] 

下面是它的工作方式:

好吧,讓我們從一個3維數組開始說明。

>>> import numpy as np 
>>> a = np.arange(24).reshape((2,3,4)) 
>>> a 
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]]]) 

您可以通過在每個軸上指定索引按如下方式訪問這個數組的元素:

>>> a[0,1,2] 
6 

這是a[0][1][2]相當於是你將如何訪問,如果我們處理相同的元素一個列表而不是一個數組。

numpy的允許您切片陣列時得到更炫:

>>> a[[0,1],[1,1],[2,2]] 
array([ 6, 18]) 
>>> a[[0,1],[1,2],[2,2]] 
array([ 6, 22]) 

這些例子就相當於[a[0][1][2],a[1][1][2]][a[0][1][2],a[1][2][2]]如果我們處理列表。

你甚至可以忽略重複的索引,numpy會找出你想要的。例如,上述實施例可以被等效地寫成:

>>> a[[0,1],1,2] 
array([ 6, 18]) 
>>> a[[0,1],[1,2],2] 
array([ 6, 22]) 

陣列(或列表)的形狀與您在每個維度切片僅影響形狀返回的數組的。換句話說,numpy並不關心你試圖用一個形狀爲(2,3,4)的數組索引你的數組,除非它將回饋一個形狀爲(2,3,4)的數組。例如:

>>> a[[[0,0],[0,0]],[[0,0],[0,0]],[[0,0],[0,0]]] 
array([[0, 0], 
     [0, 0]]) 

在這種情況下,我們斂相同元件,a[0,0,0]一遍一遍,但如我們在通過numpy的被返回的數組具有相同形狀

好的,到。你的問題。你想要的是用你的index數組中的數字爲最後一個軸上的數組編號。因此,對於你想要的問題中的例子,你需要​​3210

事實上你的索引數組是多維的,就像我之前說的那樣,並不能告訴numpy關於你想從哪裏獲取這些索引的任何事情;它只是指定了輸出數組的形狀。因此,在您的示例中,您需要告訴numpy前5個值將從a[0]中提取,後5個值將從a[1]中提取。簡單!

>>> a[[[0]*5,[1]*5],index] 

它變得複雜在N個維度,但讓我們做它的3維陣列a我方式如上所定義。假設我們有以下索引數組:

>>> i = np.array(range(4)[::-1]*6).reshape(a.shape) 
>>> i 
array([[[3, 2, 1, 0], 
     [3, 2, 1, 0], 
     [3, 2, 1, 0]], 

     [[3, 2, 1, 0], 
     [3, 2, 1, 0], 
     [3, 2, 1, 0]]]) 

所以,這些值都是針對沿着最後一個軸的索引。我們需要告訴numpy沿着第一和第二軸的這些數字是從哪些指數取得的;也就是說,我們需要告訴numpy的,對於第一軸的指標是:

i1 = [[[0, 0, 0, 0], 
     [0, 0, 0, 0], 
     [0, 0, 0, 0]], 

     [[1, 1, 1, 1], 
     [1, 1, 1, 1], 
     [1, 1, 1, 1]]] 

和第二軸的指標是:

i2 = [[[0, 0, 0, 0], 
     [1, 1, 1, 1], 
     [2, 2, 2, 2]], 

     [[0, 0, 0, 0], 
     [1, 1, 1, 1], 
     [2, 2, 2, 2]]] 

那麼我們可以這樣做:

>>> a[i1,i2,i] 
array([[[ 3, 2, 1, 0], 
     [ 7, 6, 5, 4], 
     [11, 10, 9, 8]], 

     [[15, 14, 13, 12], 
     [19, 18, 17, 16], 
     [23, 22, 21, 20]]]) 

產生i1i2的方便numpy功能稱爲np.mgrid。我在我的回答中使用了np.ogrid,這在這種情況下是相當的,因爲我之前提到過的那種無聊的魔法。

希望有幫助!

+0

我認爲你釘了我想做的事。非常感謝!不要過於貪婪,但你能解釋一下n維版本的用途嗎?我一直在玩它,但我不贊成這個動作。 –

+0

沒問題。我添加了一個解釋,順便說一下,寫出的時間比找出答案的時間長! – user545424

+0

你,先生,值得一枚勳章!感謝您的美妙回答。 –

3

與此些今天打後,我想通了,如果我捎使用的映射功能,我可以真正解決了二維版本只是這樣的:

a1 = random.standard_normal(size=[2,5]) 
index = array([[0,1,2,4,3] , [0,1,2,3,4] ]) 
map(take, a1, index) 

我需要map()take()a1

當然,接受的答案解決了n維版本。然而,回想起來,我確定我並不需要n維解決方案,而只需要2-D版本。