Эффективный метод вычисления рангового вектора списка в 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