2016-03-06 64 views
0

numpy.argsort返回一個排序列表來執行間接排序,但它似乎並不接受用戶定義的函數來比較兩個元素。Python - 如何使用用戶定義的函數執行間接排序?

我想知道如何根據與用戶定義函數的比較得出排序列表。

在我的情況,我有結果表:

a = [[1,2,3,5,6,7,8],[4,6,2,5,6,3,4],...] 

而我的函數來比較是:

def argMedian(A): 
    s = np.array([sum(A[:i+1]) for i in range(Nmentions)]) 
    mid = float(s[Nmentions-1])/2 
    return np.argwhere(mid < s)[0][0] 

def tieBreaking(A, B): 
Ac = A 
Bc = B 
medA = argMedian(Ac) 
medB = argMedian(Bc) 
while medA == medB: 
    Ac[medA] -= 1 
    Bc[medB] -= 1 
    medA = argMedian(Ac) 
    medB = argMedian(Bc) 
return 1 if medA > medB else -1 

這是majority judgment的實現。列表包含每個年級的選票數量。如果兩個列表的中位數相等,則兩個列表的中位投票都將被刪除,中位數的比較將再次進行測試。在這裏,我認爲索引0是最好的等級,索引7是最差的。

我需要執行間接排序,因爲我想知道排名。

+0

該比較函數沒有意義,因爲您使用中值作爲列表中的索引,但值的中值可能不是有效的索引。此外,即使它有效,它也會改變你的列表,這可能不是你想要的。請描述你想如何排序你的列表。 – BrenBarn

+0

嗯,我認爲只要所有的數值都不相等,中位數的上限就提供了一個有效的指數?爲了避免變更列表,我應該先複製它們?這個想法是從大多數遊戲中實現打破平局的算法:https://en.wikipedia.org/wiki/Majority_judgment#Example_application –

+2

如果你的列表是[[100,200,300]],那麼中位數是200,但200不是列表中的有效索引。 – BrenBarn

回答

0

對於基本的Python計算間接排序,一些小技巧存在。他們在Equivalent of Numpy.argsort() in basic python?進行了比較。

以最快的解決方案,可以添加比較功能。

在Python 2.7:

sorted(range(len(results)), cmp=tieBreaking, key=results.__getitem__) 

在Python 3,應注意使cmp已經消失,但功能cmp_to_key可以取代它。

0

您不需要使用numpy對列表中的元素進行排序。您可以對列表或排序()進行排序()操作。如果需要,定義您的自定義比較器。

+0

其實我真的需要執行間接排序:我想要的是知道要排序的索引,而不是排序的結果 –

1

如果您使用Python> = 3.4,則可以使用statistics.median_low()

from random import randrange 
from statistics import median_low 

a = [[randrange(8) for _ in range(7)] for _ in range(10)] 

print("unsorted") 
for item in a: 
    print(item) 

a.sort(key=median_low) 

print("\nsorted") 
for item in a: 
    print(item) 

輸出:

unsorted 
[4, 2, 2, 1, 4, 7, 4] 
[2, 2, 2, 7, 5, 5, 6] 
[3, 0, 0, 5, 5, 3, 1] 
[4, 7, 6, 2, 6, 7, 3] 
[4, 7, 7, 1, 2, 7, 7] 
[6, 2, 6, 5, 6, 7, 2] 
[7, 1, 6, 0, 0, 7, 1] 
[0, 5, 1, 2, 1, 7, 7] 
[2, 7, 6, 7, 5, 4, 7] 
[6, 5, 2, 3, 5, 0, 3] 

sorted 
[7, 1, 6, 0, 0, 7, 1] 
[0, 5, 1, 2, 1, 7, 7] 
[3, 0, 0, 5, 5, 3, 1] 
[6, 5, 2, 3, 5, 0, 3] 
[4, 2, 2, 1, 4, 7, 4] 
[2, 2, 2, 7, 5, 5, 6] 
[4, 7, 6, 2, 6, 7, 3] 
[6, 2, 6, 5, 6, 7, 2] 
[2, 7, 6, 7, 5, 4, 7] 
[4, 7, 7, 1, 2, 7, 7] 

EDIT充分替代的解決方案:

考慮排序的列表如下: 1.查找列表的median_low並將其移動到的前名單 2.查找列表[1:]的median_low並將其移至第二個地點 3.查找列表[2:]的中位數下降...

您可以按中位數值對原始列表進行排序,也可以創建按中位值對元素進行排序的鍵。

def def keyfunc(x): 
    t = x[:] 
    return [t.pop(t.index(median_low(t))) for _ in range(len(t))] 

a = [ 
    [4, 2, 2, 1, 4, 7, 4], 
    [2, 2, 2, 7, 5, 5, 6], 
    [3, 0, 0, 5, 5, 3, 1], 
    [7, 1, 6, 0, 0, 6, 1], # tie for first four rounds, but then wins 
    [4, 7, 6, 2, 6, 7, 3], 
    [6, 2, 6, 5, 6, 7, 2], 
    [7, 1, 6, 0, 0, 7, 1], # tie for first four rounds 
    [0, 5, 1, 2, 1, 7, 7], 
    [2, 7, 6, 7, 5, 4, 7], 
    [6, 5, 2, 3, 5, 0, 3] 
] 

a.sort(key=keyfunc) 

print("\nsorted") 
for item in a: 
    print(item) 

輸出:

sorted 
[7, 1, 6, 0, 0, 6, 1] 
[7, 1, 6, 0, 0, 7, 1] 
[0, 5, 1, 2, 1, 7, 7] 
[3, 0, 0, 5, 5, 3, 1] 
[6, 5, 2, 3, 5, 0, 3] 
[4, 2, 2, 1, 4, 7, 4] 
[2, 2, 2, 7, 5, 5, 6] 
[4, 7, 6, 2, 6, 7, 3] 
[6, 2, 6, 5, 6, 7, 2] 
[2, 7, 6, 7, 5, 4, 7] 
+0

這是一個好主意,但是在平等的情況下,打破平局的算法會拋出一個等級。不幸的是,沒有內置函數可以做到這一點。 –

+1

正如wikipeadia頁面所說的:如果贏家平局,那麼取平均值,刪除中間值,然後重新排序。重複,直到你有一個勝利者。使用'list.remove()'從列表中刪除一個特定的值。 – RootTwo

相關問題