45

rankR の関数と同様に、Python でリストのランク ベクトルを計算する効率的な方法を探しています。要素間に関係がない単純なリストでは、並べ替えられたリストのx番目の要素である場合に限り、リストのランク ベクトルの要素iはxになります。ここまでは簡単です。次のコード スニペットでうまくいきます。ll[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でこれを行う最も効率的な方法はどれですか?


脚注: NumPy がこれを達成する方法を既に持っているかどうかはわかりません。その場合はお知らせください。ただし、NumPy がなくても機能するツールを開発しているので、とにかく純粋な Python ソリューションに興味があります。

4

13 に答える 13

78

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.])

ランクは(あなたの例のように)0ではなく1から始まりますが、それがRrank機能も同様に機能する方法です。

scipyrankdata関数に相当する純粋な Python は次のとおりです。

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]
于 2010-06-18T16:30:45.947 に答える
6

これは、ランクを計算するために作成した関数の 1 つです。

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]
于 2016-12-03T22:36:51.683 に答える
4

これはあなたが指定した正確な結果を与えるわけではありませんが、とにかく役に立つでしょう。次のスニペットは、各要素の最初のインデックスを提供し、最終的なランク ベクトルを生成します。[0, 1, 2, 2, 2, 5, 6]

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

独自のテストで、この効率性を証明する必要があります。

于 2010-06-18T16:49:10.910 に答える
3

以下は unutbu のコードの小さなバリエーションで、同順位の値の型を指定するオプションの「メソッド」引数が含まれています。

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
于 2015-06-12T11:20:53.567 に答える
2

Ranking http://pythonhosted.org/ranking/という非常に優れたモジュールがあり、わかりやすい説明ページがあります。ダウンロードするには、単に使用しますeasy_install ranking

于 2013-09-05T10:25:13.597 に答える
1

配列のランクを見つけるための最もpythonicなスタイル:

a = [10.0, 9.8, 8.0, 7.8, 7.7, 7.0, 6.0, 5.0, 4.0, 2.0]
rank = lambda arr: list(map(lambda i: sorted(arr).index(i)+1, arr))
rank(a)
于 2021-08-17T04:56:19.673 に答える
0

これらのコード、特に 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
于 2016-01-06T08:28:20.117 に答える
0

これは、スピアマンの相関係数に対して機能します。

def get_rank(X, n):
    x_rank = dict((x, i+1) for i, x in enumerate(sorted(set(X))))
    return [x_rank[x] for x in X]
于 2020-08-07T06:36:49.510 に答える