Эффективный метод вычисления рангового вектора списка в Python

Я ищу эффективный способ вычисления вектора ранга списка в Python, аналогичного R

7 ответов


используя scipy, функция, которую вы ищете, является scipy.статистика.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.])

ряды начинаются с 1, а не 0 (как в вашем примере), но опять же, вот так R ' s rank функция работает также.

вот чистый эквивалент 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]

это не дает точного результата, который вы указываете, но, возможно, это было бы полезно в любом случае. Следующий фрагмент дает первый индекс для каждого элемента, уступая место вектор [0, 1, 2, 2, 2, 5, 6]

def rank_index(vector):
    return [vector.index(x) for x in sorted(range(n), key=vector.__getitem__)]

ваше собственное тестирование должно было бы доказать эффективность этого.


есть действительно хороший модуль под названием Ranking http://pythonhosted.org/ranking/ с легкой для следования страницы инструкции. Чтобы загрузить, просто используйте easy_install ranking


вот небольшая вариация кода unutbu, включая необязательный аргумент "method" для типа значения связанных рангов.

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

def rankdata(a, method='average'):
    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]:
            for j in xrange(i-dupcount+1,i+1):
                if method=='average':
                    averank = sumranks / float(dupcount) + 1
                    newarray[ivec[j]] = averank
                elif method=='max':
                    newarray[ivec[j]] = i+1
                elif method=='min':
                    newarray[ivec[j]] = i+1 -dupcount+1
                else:
                    raise NameError('Unsupported method')

            sumranks = 0
            dupcount = 0


    return newarray

Это одна из функций, которую я написал для вычисления ранга.

   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]

вход: calculate_rank([1,3,4,8,7,5,4,6])
выход: [1, 2, 3, 7, 6, 4, 3, 5]


import numpy as np

def rankVec(arg):
    p = np.unique(arg) #take unique value
    k = (-p).argsort().argsort() #sort based on arguments in ascending order
    dd = defaultdict(int)
    for i in xrange(np.shape(p)[0]):
        dd[p[i]] = k[i]
    return np.array([dd[x] for x in arg])

timecomplexity-46.2 us


эти коды дают мне много вдохновения, особенно код unutbu по. Однако мои потребности проще, поэтому я немного изменил код.

надеясь помочь ребятам с теми же потребностями.

вот класс для записи очков и рангов игроков.

class Player():
    def __init__(self, s, r):
        self.score = s
        self.rank = r

некоторые данные.

l = [Player(90,0),Player(95,0),Player(85,0), Player(90,0),Player(95,0)]

вот код для расчета:

l.sort(key=lambda x:x.score, reverse=True)    
l[0].rank = 1
dupcount = 0
prev = l[0]
for e in l[1:]:
    if e.score == prev.score:
        e.rank = prev.rank
        dupcount += 1
    else:
        e.rank = prev.rank + dupcount + 1
        dupcount = 0
        prev = e