2015-04-02 57 views
1

我有兩個排序的詞典,即它們現在表示爲列表。 我想檢索每個列表中每個元素的排名位置並將其存儲在一個變量中,以便最終我可以計算兩個列表中每個元素的排名分數的加權平均值。這是一個例子。檢索各種列表中的元素排名,以計算其排名分數的加權平均值Python

dict1 = {'class1': 15.17, 'class2': 15.95, 'class3': 15.95}

​​

sorted_dict2 = [('class2', 9.10), ('class3', 9.22), ('class1', 10.60)] 

到目前爲止,我可以檢索列表中的每個元素的排名位置,並打印的排名,但是當我嘗試計算排名分數的即加權平均[ (w1 * a + w2 * b)/(w1 + w2)],其中「a」是sorted_dict1中的排名位置,「b」是sorted_dict2中的排名位置,我得到的數字不是正確的加權平均數。

嘗試不同的東西,這裏是一個:

for idx, val in list(enumerate(sorted_dict1, 1)): 
    for idx1, val1 in list(enumerate(sorted_dict2, 1)): 
     position_dict1 = idx 
     position_dict2 = idx1 
    weighted_average = float((0.50*position_dict1 + 0.25*position_dict2))/0.75  
    print weighted_average 

我還沒有考慮,如果兩個類均居同在一個列表中會發生什麼。我會很感激得到任何提示/幫助。

我認爲我可能需要創建一個函數來解決這個問題,但我沒有去那麼遠。

任何幫助以及隨附的解釋代碼的評論都會很棒。

所以我想計算列表中元素排名位置的加權平均值。例如的加權平均爲:

的Class1: weighted_average =((0.50 * 1)+(0.25 * 3))/ 0.75 = 1.5

等級2: 則weighted_average =((0.50 * 2)+( 0.25 * 1))/ 0.75 = 1.6666..7

謝謝!

+0

字典是按值還是按鍵「排序」? – pzp 2015-04-02 13:01:55

+0

嗨字典按價值排序,按升序排列。我以前對打字錯誤抱歉。 – HR123r 2015-04-02 13:08:34

+0

元素在其各自的排序列表中或整體上的位置是''a'''和'''b'''嗎?我在你的代碼中看到它們的值是0.5和0.25,不能是索引。 – pzp 2015-04-02 13:15:30

回答

1

我已經採取簡單的方法,給予同等分數的類下一個整數排名,所以class3class2都有等級2 sorted_dict1

#!/usr/bin/env python 

#Get the ranks for a list of (class, score) tuples sorted by score 
#and return them in a dict 
def get_ranks(sd): 
    #The first class in the list has rank 1 
    k, val = sd[0] 
    r = 1 
    rank = {k: r} 

    for k, v in sd[1:]: 
     #Only update the rank number if this value is 
     #greater than the previous 
     if v > val: 
      val = v 
      r += 1 
     rank[k] = r 
    return rank 

def weighted_mean(a, b): 
    return (0.50*a + 0.25*b)/0.75 

sorted_dict1 = [('class1', 15.17), ('class2', 15.95), ('class3', 15.95)] 
sorted_dict2 = [('class2', 9.10), ('class3', 9.22), ('class1', 10.60)] 

print sorted_dict1 
print sorted_dict2 

ranks1 = get_ranks(sorted_dict1) 
ranks2 = get_ranks(sorted_dict2) 

print ranks1 
print ranks2 

keys = sorted(k for k,v in sorted_dict1) 

print [(k, weighted_mean(ranks1[k], ranks2[k])) for k in keys] 

輸出

[('class1', 15.17), ('class2', 15.949999999999999), ('class3', 15.949999999999999)] 
[('class2', 9.0999999999999996), ('class3', 9.2200000000000006), ('class1', 10.6)] 
{'class2': 2, 'class3': 2, 'class1': 1} 
{'class2': 1, 'class3': 2, 'class1': 3} 
[('class1', 1.6666666666666667), ('class2', 1.6666666666666667), ('class3', 2.0)] 

在我提到的評論中有一個很好的方法來創建一個weighted_mean()函數w自定義權重。當然,我們可能只是將權重作爲附加參數傳遞給weighted_mean(),但這會使weighted_mean()的調用比需要的更加混亂,從而使程序難以閱讀。

訣竅是使用將自定義權重作爲參數並返回所需函數的函數。從技術上講,這種功能製作功能被稱爲closure

下面是如何做到這一點的簡短演示。

#!/usr/bin/env python 

#Create a weighted mean function with weights w1 & w2 
def make_weighted_mean(w1, w2): 
    wt = float(w1 + w2) 
    def wm(a, b): 
     return (w1 * a + w2 * b)/wt 
    return wm 

#Make the weighted mean function 
weighted_mean = make_weighted_mean(1, 2) 

#Test 
print weighted_mean(6, 3) 
print weighted_mean(3, 9) 

輸出

4.0 
7.0 

這裏的第一個程序的更新版本高於處理sorted_dict列出任意數量。它使用原始的get_ranks()函數,但它使用比上述示例更復雜的閉包來執行數據列表(或元組)上的加權平均值。

#!/usr/bin/env python 

''' Weighted means of ranks 

    From https://stackoverflow.com/q/29413531/4014959 

    Written by PM 2Ring 2015.04.03 
''' 

from pprint import pprint 

#Create a weighted mean function with weights from list/tuple weights 
def make_weighted_mean(weights): 
    wt = float(sum(weights)) 
    #A function that calculates the weighted mean of values in seq 
    #weighted by the weights passed to make_weighted_mean() 
    def wm(seq): 
     return sum(w * v for w, v in zip(weights, seq))/wt 
    return wm 


#Get the ranks for a list of (class, score) tuples sorted by score 
#and return them in a dict 
def get_ranks(sd): 
    #The first class in the list has rank 1 
    k, val = sd[0] 
    r = 1 
    rank = {k: r} 

    for k, v in sd[1:]: 
     #Only update the rank number if this value is 
     #greater than the previous 
     if v > val: 
      val = v 
      r += 1 
     rank[k] = r 
    return rank 


#Make the weighted mean function 
weights = [0.50, 0.25] 
weighted_mean = make_weighted_mean(weights) 

#Some test data 
sorted_dicts = [ 
    [('class1', 15.17), ('class2', 15.95), ('class3', 15.95), ('class4', 16.0)], 
    [('class2', 9.10), ('class3', 9.22), ('class1', 10.60), ('class4', 11.0)] 
] 
print 'Sorted dicts:' 
pprint(sorted_dicts, indent=4) 

all_ranks = [get_ranks(sd) for sd in sorted_dicts] 
print '\nAll ranks:' 
pprint(all_ranks, indent=4) 

#Get a sorted list of the keys 
keys = sorted(k for k,v in sorted_dicts[0]) 
#print '\nKeys:', keys 

means = [(k, weighted_mean([ranks[k] for ranks in all_ranks])) for k in keys] 
print '\nWeighted means:' 
pprint(means, indent=4) 

輸出

Sorted dicts: 
[ [ ('class1', 15.17), 
     ('class2', 15.949999999999999), 
     ('class3', 15.949999999999999), 
     ('class4', 16.0)], 
    [ ('class2', 9.0999999999999996), 
     ('class3', 9.2200000000000006), 
     ('class1', 10.6), 
     ('class4', 11.0)]] 

All ranks: 
[ { 'class1': 1, 'class2': 2, 'class3': 2, 'class4': 3}, 
    { 'class1': 3, 'class2': 1, 'class3': 2, 'class4': 4}] 

Weighted means: 
[ ('class1', 1.6666666666666667), 
    ('class2', 1.6666666666666667), 
    ('class3', 2.0), 
    ('class4', 3.3333333333333335)] 

而且這裏有get_ranks()的替代版本,跳過等級號碼如果有兩個或多個類均居同在一個列表

def get_ranks(sd): 
    #The first class in the list has rank 1 
    k, val = sd[0] 
    r = 1 
    rank = {k: r} 
    #The step size from one rank to the next. Normally 
    #delta is 1, but it's increased if there are ties. 
    delta = 1 

    for k, v in sd[1:]: 
     #Update the rank number if this value is 
     #greater than the previous. 
     if v > val: 
      val = v 
      r += delta 
      delta = 1 
     #Otherwise, update delta 
     else: 
      delta += 1 
     rank[k] = r 
    return rank 

這裏的輸出該程序使用get_ranks()的替代版本:

Sorted dicts: 
[ [ ('class1', 15.17), 
     ('class2', 15.949999999999999), 
     ('class3', 15.949999999999999), 
     ('class4', 16.0)], 
    [ ('class2', 9.0999999999999996), 
     ('class3', 9.2200000000000006), 
     ('class1', 10.6), 
     ('class4', 11.0)]] 

All ranks: 
[ { 'class1': 1, 'class2': 2, 'class3': 2, 'class4': 4}, 
    { 'class1': 3, 'class2': 1, 'class3': 2, 'class4': 4}] 

Weighted means: 
[ ('class1', 1.6666666666666667), 
    ('class2', 1.6666666666666667), 
    ('class3', 2.0), 
    ('class4', 4.0)] 
+0

嗨PM 2Ring,謝謝你的回答。我不確定代碼def(get_ranks(sd))的這一部分是什麼,特別是當你只更新等級號碼時,如果該值大於前一個: ,並且例如不應該是等級等級的加權平均值一個等於1.5,而不是1.6667?因此,在sorted_dict1中,class2和class3確實具有相同的排名,即爲2,因此class4將具有3或4的排名?謝謝 – HR123r 2015-04-02 14:29:07

+0

@ HR123r:'((0.50 * 1)+(0.25 * 3))/ 0.75 = 1.666666 ...'如果該值大於前一個值,我只更新等級編號,以便得到相同等級的等級,正如我在[評論](http://stackoverflow.com/questions/29413531/retrieve-the-ranking-of-elements-in-various-list-to-compute-the-weighted-average/29415131#comment47001515_29413531)。使用該方案a class4將有下一個排名3,因爲class2和class3共享第二名:就像他們合併我一樣nto一個班。 – 2015-04-02 14:36:16

+0

對不起,如果這不是你想如何處理相同分數的類,但我開始編寫代碼之前讓我評論一段時間,並且你還沒有回覆......但是修改我的'get_ranks()'並不難。函數給class4 4級(參考上面的例子)。 – 2015-04-02 14:38:35