Python 不跳数排名(密排)

Python ranking without skipping number (dense rank)

使用 python 3.x 我想实现密集排名(如果排名重复,不要跳过数字)。我根据分数

对以下数组进行了排序
rank_list = [{'Id': 236966, 'score': 91.0}, {'Id': 237241, 'score': 82.0}, {'Id': 237077, 'score': 79.0}, {'Id': 237084, 'score': 78.0}, {'Id': 237080, 'score': 72.0}, {'Id': 237236, 'score': 71.0}, {'Id': 236979, 'score': 71.0}, {'Id': 236909, 'score': 67.0}, {'Id': 237174, 'score': 67.0}, {'Id': 237035, 'score': 66.0}] 

我使用下面的代码来计算和分配 'rank' 字段,但是如果有重复的排名,代码会跳过一个排名

def rankFunc(e):
    return e['score']

rank_list.sort(key = rankFunc, reverse=True)
sorted_scores = [obj['score'] for obj in rank_list]
ranks = [sorted_scores.index(x) for x in sorted_scores]
for index, obj in enumerate(rank_list):
    obj['rank'] = ranks[index]+1

当前输出:

排名 = [1, 2, 3, 4, 5, 6, 6, 8, 8, 10]

我希望在不跳过任何数字的情况下分配等级,

排名 = [1, 2, 3, 4, 5, 6, 6, 7, 7, 8]

这个小辅助函数应该可以解决您的问题:

def rank_unique(x, **kwargs):
    sx = sorted(set(x), **kwargs)
    invsx = {s: i for i, s in enumerate(sx)}
    return [1 + invsx[v] for v in x]

>>> rank_unique([r["score"] for r in rank_list], reverse=True)
[1, 2, 3, 4, 5, 6, 6, 7, 7, 8]

这个简单的解决方案将解决您的问题(假设数组已经排序)。

def assignRank(_list):
    rank = 0
    for i in range(len(_list)):
        if _list[i]["score"] != _list[i-1]["score"]:
            rank += 1
        _list[i]["rank"] = rank

您可以使用具有 pandas 函数的密集排序方法

import pandas as pd
rank = pd.Series(sorted_scores).rank(method="dense",ascending=False).values
print(rank)

输出:

[1. 2. 3. 4. 5. 6. 6. 7. 7. 8.]