在Python中计算列表的秩向量的有效方法

Tam*_*más 27 python sorting list ranking

我正在寻找一种有效的方法来计算Python中列表的秩向量,类似于R的rank函数.在元素之间没有联系的简单列表中,列表的等级向量的元素il应该是x,当且仅当l[i]是排序列表中的第x个元素时.到目前为止,这很简单,以下代码片段可以解决这个问题:

def rank_simple(vector):
    return sorted(range(len(vector)), key=vector.__getitem__)
Run Code Online (Sandbox Code Playgroud)

然而,如果原始列表具有联系(即具有相同值的多个元素),则事情变得复杂.在这种情况下,具有相同值的所有元素应该具有相同的等级,这是使用上述朴素方法获得的等级的平均值.所以,例如,如果我有[1, 2, 3, 3, 3, 4, 5],天真的排名给了我[0, 1, 2, 3, 4, 5, 6],但我想拥有的是[0, 1, 3, 3, 3, 5, 6].在Python中哪一个是最有效的方法?


脚注:我不知道NumPy是否已经有了实现这一目标的方法; 如果确实如此,请告诉我,但无论如何我都会对纯Python解决方案感兴趣,因为我正在开发一个在没有NumPy的情况下也可以工作的工具.

unu*_*tbu 57

使用scipy,您正在寻找的函数是scipy.stats.rankdata:

In [13]: import scipy.stats as ss
In [19]: ss.rankdata([3, 1, 4, 15, 92])
Out[19]: array([ 2.,  1.,  3.,  4.,  5.])

In [20]: ss.rankdata([1, 2, 3, 3, 3, 4, 5])
Out[20]: array([ 1.,  2.,  4.,  4.,  4.,  6.,  7.])
Run Code Online (Sandbox Code Playgroud)

队伍从1开始,而不是0(如在你的例子),但话又说回来,就是这样Rrank功能的工作原理也是如此.

这是一个纯粹的python等价scipy的rankdata函数:

def rank_simple(vector):
    return sorted(range(len(vector)), key=vector.__getitem__)

def rankdata(a):
    n = len(a)
    ivec=rank_simple(a)
    svec=[a[rank] for rank in ivec]
    sumranks = 0
    dupcount = 0
    newarray = [0]*n
    for i in xrange(n):
        sumranks += i
        dupcount += 1
        if i==n-1 or svec[i] != svec[i+1]:
            averank = sumranks / float(dupcount) + 1
            for j in xrange(i-dupcount+1,i+1):
                newarray[ivec[j]] = averank
            sumranks = 0
            dupcount = 0
    return newarray

print(rankdata([3, 1, 4, 15, 92]))
# [2.0, 1.0, 3.0, 4.0, 5.0]
print(rankdata([1, 2, 3, 3, 3, 4, 5]))
# [1.0, 2.0, 4.0, 4.0, 4.0, 6.0, 7.0]
Run Code Online (Sandbox Code Playgroud)


小智 18

[sorted(l).index(x) for x in l]
Run Code Online (Sandbox Code Playgroud)

sorted(l)将给出排序版本 index(x)将给出index排序数组中的

例如 :

l = [-1, 3, 2, 0,0]
>>> [sorted(l).index(x) for x in l]
[0, 4, 3, 1, 1]
Run Code Online (Sandbox Code Playgroud)

  • 不错的单线!考虑到效率,这是否对“l”中的每个“x”重复排序?顺便说一句,它返回并列排名的最低指数,而不是平均值,这是另一个有用的选项,但不完全是OP所要求的。 (2认同)

小智 6

这是我为计算排名而编写的函数之一。

def calculate_rank(vector):
  a={}
  rank=1
  for num in sorted(vector):
    if num not in a:
      a[num]=rank
      rank=rank+1
  return[a[i] for i in vector]
Run Code Online (Sandbox Code Playgroud)

输入:

calculate_rank([1,3,4,8,7,5,4,6])
Run Code Online (Sandbox Code Playgroud)

输出:

[1, 2, 3, 7, 6, 4, 3, 5]
Run Code Online (Sandbox Code Playgroud)