我正在寻找一种类似于Rrank函数的高效方法来计算Python中列表的秩向量。在一个简单的列表与所述元件之间没有联系,元件 我 的列表的秩矢量的l应该是 X 当且仅当l[i]是 X 个在排序的列表元素。到目前为止,这很简单,以下代码片段可以解决问题:
rank
l
l[i]
def rank_simple(vector): return sorted(range(len(vector)), key=vector.__getitem__)
但是,如果原始列表具有联系(即,多个具有相同值的元素),事情就会变得复杂。在这种情况下,所有具有相同值的元素都应具有相同的等级,这是使用上述朴素方法获得的等级的平均值。因此,例如,如果我有[1, 2, 3, 3, 3, 4, 5],那么天真的排名会给我[0, 1, 2, 3, 4, 5, 6],但是我想拥有的是[0, 1, 3, 3, 3, 5, 6]。在Python中,哪一种是最有效的方法?
[1, 2, 3, 3, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 3, 3, 3, 5, 6]
脚注:我不知道NumPy是否已经有实现此目标的方法。如果可以的话,请告诉我,但是无论如何,我将对纯Python解决方案感兴趣,因为我正在开发一种也可以在没有NumPy的情况下使用的工具。
使用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.])
队伍从1开始,而不是0(如在你的例子),但话又说回来,就是这样R的rank功能的作品也是如此。
R
这是scipy的rankdata函数的纯Python等效项:
scipy
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]