2014-09-21 45 views
4

用numpy,你可以做間接排序。也就是說,從像用Numpy間接排序

>> a = array([ 8, 10, 5, 2, 3, 1, 6]) 

數組,然後做一個間接的排序是這樣的:

>> np.argsort(a) 
>> array([5, 3, 4, 2, 6, 0, 1]) 

這個數組類似於「在有序陣列的第0個位置應該是a[5]輸入數組之一,有序數組的第1個位置應爲a[3]「等等。但是,是否有一種Numpy驅動的方式來獲得像「應該在這裏」排序的東西?我是什麼意思?使用argsort,你有索引排序命令輸入數組,所以a[np.argsort(a)]是一個有序數組。但是,我需要的是相反的方式,也就是說,對於輸入數組的每個元素,獲取有序數組上的元素位置。對於例如:

>>myweirdsort(a) 
>>array([5, 6, 3, 1, 2, 0, 4]) 

這個數組類似於「a[0]雲在有序排列的5個位置,a[1]雲在有序排列的6個位置」等上。順便說一下,當我說「Numpy-powered」時,我的意思是一種矢量化的Numpy-ish方式來做到這一點。非Numpy方式應該是遍歷每個元素,做一些類似於數組的分區,然後確定元素在分區數組中的位置,但這會花費太長時間。

回答

4

雖然@ BrenBarn的解決方案是完全有效的,非常緊湊,並在numpy的代碼通常的結構,你有兩次排序,它總是讓我吃驚因爲有點浪費。事實證明,你不必做第二種。下面的代碼並不簡單,但對於大型陣列來說會更快:

>>> my_weird_sort = np.empty_like(idx) 
>>> my_weird_sort[idx] = np.arange(idx.size) 

>>> my_weird_sort 
array([5, 6, 3, 1, 2, 0, 4]) 

快多少?我做了一些計時,在我的系統上,對於小尺寸,速度稍微慢一點,對於〜100-200個物品的數組,啓動速度更快,對於1,000至1,000,000個物品的數組,速度要快1.4-1.5倍。


爲了完整起見,類似的構建體通常被用於第一個排序的陣列,獲得排序後的數組中的每一項的某個值,然後重新排列的結果返回到未排序的狀態。作爲一個例子,以找出是否一個項目是一個數組值的第一個實例,你可以這樣做:

>>> b = np.array([1, 3, 1, 2, 4, 3, 3, 2, 0]) 
>>> idx = np.argsort(b, kind='mergesort') # need stable sort 
>>> sorted_b = b[idx] 
>>> sorted_b 
array([0, 1, 1, 2, 2, 3, 3, 3, 4]) 
>>> sorted_is_first = np.concatenate(([True], sorted_b[1:] != sorted_b[:-1])) 
>>> sorted_is_first 
array([ True, True, False, True, False, True, False, False, True], dtype=bool) 
>>> is_first = sorted_is_first[idx.argsort()] 
>>> is_first 
array([ True, True, False, True, True, False, False, False, True], dtype=bool) 

你也可以得到這個沒有第二個排序,由同樣做上面:

>>> is_first = np.empty_like(sorted_is_first) 
>>> is_first[idx] = sorted_is_first 
>>> is_first 
array([ True, True, False, True, True, False, False, False, True], dtype=bool) 

與此類似最近添加到np.unique,對於被要求return_inverse指標的情況下的變化,看到here。在那種情況下,大尺寸的速度幾乎是2倍。

+0

相關:http://stackoverflow.com/a/25535723/166749 – 2014-09-21 15:41:24

+0

哇!我發送該公關時大約在同一天的時間,阿里發佈了他的回覆給其他線程... – Jaime 2014-09-21 16:27:24

+0

我知道,當我看到公關我立即檢查是否你是誰發佈的答案:) – 2014-09-21 20:22:36

6

你只需要再次argsort的argsort:

>>> a.argsort().argsort() 
array([5, 6, 3, 1, 2, 0, 4], dtype=int64)