2009-12-14 63 views
29

如果我有兩個平行的清單,並希望通過在第一個元素的順序對它們進行排序,這是非常容易的:如何「zip排序」並行numpy數組?

>>> a = [2, 3, 1] 
>>> b = [4, 6, 2] 
>>> a, b = zip(*sorted(zip(a,b))) 
>>> print a 
(1, 2, 3) 
>>> print b 
(2, 4, 6) 

我怎麼能一樣使用numpy的陣列做不拆包他們進入常規Python列表?

+1

@YGA,你的輸入數組「a」有沒有非唯一的值?如果是這樣,那麼在這種情況下你會喜歡這種行爲?任意訂單?穩定的排序?使用數組「b」中的相應值進行二次排序? –

回答

40

b[a.argsort()]應該這樣做。

這是它的工作原理。首先,你需要找到排序的排列。 argsort的是,這個計算方法:

>>> a = numpy.array([2, 3, 1]) 
>>> p = a.argsort() 
>>> p 
[2, 0, 1] 

可以輕鬆地檢查,這是正確的:

>>> a[p] 
array([1, 2, 3]) 

現在應用相同的置換到b。

>>> b = numpy.array([4, 6, 2]) 
>>> b[p] 
array([2, 4, 6]) 
+2

這不使用'b'作爲「輔助排序」,例如當'a'包含重複的元素時。詳情請看我的答案。 –

+1

otoh,輔助排序並不總是需要。 – tacaswell

19

這是一種不創建中間Python列表的方法,雖然它確實需要一個NumPy「記錄數組」用於排序。如果你的兩個輸入數組實際上是相關的(比如電子表格中的列),那麼這可能會打開一個有利的方式來處理你的數據,而不是始終保持兩個不同的數組,在這種情況下,你已經有了一個記錄數組和你原來的問題只會通過在你的數組上調用sort()來回答。

這確實一個in-place sort包裝兩個陣列成記錄陣列之後:

>>> from numpy import array, rec 
>>> a = array([2, 3, 1]) 
>>> b = array([4, 6, 2]) 
>>> c = rec.fromarrays([a, b]) 
>>> c.sort() 
>>> c.f1 # fromarrays adds field names beginning with f0 automatically 
array([2, 4, 6]) 

編輯使用rec.fromarrays()爲簡單起見,跳過冗餘D型細胞,使用默認排序鍵,使用默認字段名而不是指定(基於this example)。

+0

謝謝!我真的希望我能接受兩個答案。這個不那麼簡單,但更一般。我已經upvoted儘管,至少我可以做:-) – YGA

2

這可能是最簡單也是最普遍的做法。 (我在這裏使用了三個數組,但是這將適用於任何形狀的數組,無論是兩列還是兩百列)。

import numpy as NP 
fnx = lambda : NP.random.randint(0, 10, 6) 
a, b, c = fnx(), fnx(), fnx() 
abc = NP.column_stack((a, b, c)) 
keys = (abc[:,0], abc[:,1])   # sort on 2nd column, resolve ties using 1st col 
indices = NP.lexsort(keys)  # create index array 
ab_sorted = NP.take(abc, indices, axis=0) 

一個怪癖W/lexsort是,你必須按相反的順序來指定鍵,即把你的主鍵,第二和您的第二個關鍵第一。在我的例子中,我想使用第二列作爲主鍵排序,所以我列出第二個;第一列僅解析關係,但是它首先列出)。

+0

很好的抓住布倫丹,謝謝。 – doug