【问题标题】:python ranking a list of values, using average rank for non-unique valuespython对值列表进行排名,使用非唯一值的平均排名
【发布时间】:2012-11-26 01:41:15
【问题描述】:

是否有更pythonic、更快的希望按值对字典进行排名并对非唯一值的排名进行平均。我的做法:

d = {'a':5,'b':5,'c':5,'d':1,'e':6}
ordered_keys = sorted(d, key=d.get)
ordered_v = [d[k] for k in ordered_keys]
value_rank = [(ordered_v.index(v)+1)+(ordered_v.count(v)-1)/2 for v in ordered_v]
ranked_key_list = zip(ordered_keys,value_rank)
[('d', 1), ('a', 3), ('c', 3), ('b', 3), ('e', 5)]

关于排序字典的广泛讨论非常有帮助:python dictionary values sorting

【问题讨论】:

  • @the_wolf 感谢您指出这一点。我的代码中没有。我试图把事情说清楚

标签: python


【解决方案1】:

你的算法的瓶颈是 .index 和 .count 是 O(n),因此你的瓶颈是这条线:

value_rank = [(ordered_v.index(v)+1)+(ordered_v.count(v)-1)/2 for v in ordered_v]

导致你的整体表现为 O(n^2)

我为你做了一个 O(n*log(n)) 算法(瓶颈现在是排序):

import collections

d = {'a':5,'b':5,'c':5,'d':1,'e':6}
my_d = collections.defaultdict(list)
for key, val in d.items():
    my_d[val].append(key)

ranked_key_list = [] 
n = v = 1
for _, my_list in sorted(my_d.items()):
    v = n + (len(my_list)-1)/2 
    for e in my_list:
        n += 1
        ranked_key_list.append((e, v))

【讨论】:

  • 你的 O(n) 中的 n 是多少?当然它不可能是字典中的项目数,因为sorted() 是 O(n*lg(n))。
  • 很棒的答案。谢谢俄佐立!
  • @Cole 正如你从 lqc 中看到的那样,我撒谎的线现在是 O(n) 而不是 O(n^2) 但整体算法仍然是 O(nlog(n)) 因为排序
  • 非常感谢!我实际上需要那个解决方案来解决我的问题。
  • 我只有一个补充:如果这是您的目标,您需要将除法更改为 2。才能获得真正的平均排名。
【解决方案2】:

你所拥有的非常好,我怀疑是否有更短的解决方案。

至于效率,重复使用list.index()list.count() 可能会降低大型数据集的效率。

如果您要对大量数据执行此操作,那么这里是一种更有效的替代实现:

from itertools import groupby

d = {'a':5,'b':5,'c':5,'d':1,'e':6}
ranked_key_list = []
i = 1
for k, g in groupby(sorted(d.keys(), key=d.get), key=d.get):
    g = list(g)
    rank = i + (len(g)-1) / 2
    ranked_key_list.extend((k, rank) for k in g)
    i += len(g)

【讨论】:

  • 这几乎是与公认答案相同的算法,但应该更快,因为它使用groupby 对密钥进行分组。如果有很多重复键,这可能会更慢(因为它对整个键列表进行排序,而不仅仅是对重复键的集合进行排序)。
【解决方案3】:
key_list = zip(dict.keys(), dict.values())
ranked_key_list = sorted(key_list, key=lambda x: x[1])

编辑:刚刚意识到我没有做平均值的事情......你能再澄清一点吗? 3个5s = 3的平均值怎么算??

【讨论】:

  • 这不是平均,而是平均排名,所以最低 = 1,最高 = 长度,所以 1 = 1,所有 5 = 3,因为 5 排名第 2 3 和第 4 和(2 +3+4)/3 = 3 - 还有:dict.items() 和你的滑索一样
  • @cameron 没有平均的键的排名将是 [('d',1),('a',2),('b',3),('c',4 ),('e',5)]。 'a','b','c' 具有相同的值。他们的平均排名是[2,3,4]的平均值
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-07
  • 1970-01-01
相关资源
最近更新 更多