2015-04-02 3 views
1

У меня есть два отсортированных словаря, то есть они теперь представлены в виде списков. Я хотел бы получить позицию ранжирования каждого элемента в каждом из списков и сохранить его в переменной, чтобы в конечном итоге я смог вычислить средневзвешенное значение ранжирования каждого элемента в обоих списках. Вот пример.Получить ранжирование элементов в разных списках, чтобы вычислить средневзвешенное значение их ранжирования Python

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

sorted_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

class2: то weighted_average = ((0,50 * 2) + (0,25 * 1))/0,75 = 1,6666..7

Спасибо!

+0

Является ли dict «отсортированным» по значению или по ключу? – pzp

+0

Привет, словари сортируются по значению в порядке возрастания. Я прошу прощения за опечатку раньше. – HR123r

+0

Является '' '' '' '' и '' '' '' позицию элементов в их отсортированных списках или в целом? Я вижу в вашем коде, что они имеют значения 0.5 и 0.25, которые не могут быть индексами. – pzp

ответ

1

Я взял легкий путь и с учетом классов равного балла следующий целочисленный ранг, так class3 и class2 оба имеют ранг 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 класс2 и класс3 действительно имеют равный рейтинг, то есть 2. И, таким образом, класс 4 имел бы рейтинг 3? или 4? Спасибо. – HR123r

+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, поскольку оба класса2 и класс3 разделяют 2-е место: похоже, что они объединены i nto один класс. –

+0

Извините, если вы не хотите, чтобы классы с равной оценкой обрабатывались, но я _did_ комментировал некоторое время, прежде чем начал кодирование, и вы не ответили ... но изменить его 'get_ranks()' не так уж сложно, чтобы дать классу 4 ранг 4 (в соответствии с вашим примером выше). –

 Смежные вопросы

  • Нет связанных вопросов^_^