2016-07-09 11 views
2

n番目のランク付けされた値を見つけてカラム名を返す方法を見つけようとしています。たとえば、データフレームが与えられた場合:データフレームの行ごとにn番目にランク付けされたカラムIDを取得する - Python/Pandas

df = pd.DataFrame(np.random.randn(5, 4), columns = list('ABCD')) 

# Return column name of "MAX" value, compared to other columns in any particular row. 

df['MAX1_NAMES'] = df.idxmax(axis=1) 

print df 

      A   B   C   D MAX1_NAMES 
0 -0.728424 -0.764682 -1.506795 0.722246   D 
1 1.305500 -1.191558 0.068829 -1.244659   A 
2 -0.175834 -0.140273 1.117114 0.817358   C 
3 -0.255825 -1.534035 -0.591206 -0.352594   A 
4 -2.408806 -1.925055 -1.797020 2.381936   D 

これは、行の中で最も高い値を見つけ、発生した列の名前を返します。

MAX2_NAMES行で二番目に大きい値である
  A   B   C   D MAX1_NAMES MAX2_NAMES 
0 -0.728424 -0.764682 -1.506795 0.722246   D   A 
1 1.305500 -1.191558 0.068829 -1.244659   A   C 
2 -0.175834 -0.140273 1.117114 0.817358   C   D 
3 -0.255825 -1.534035 -0.591206 -0.352594   A   D 
4 -2.408806 -1.925055 -1.797020 2.381936   D   C 

:しかし、私は、私が所望の値の特定のランクを選択し、うまくいけば、次のようなデータフレームを取得することができますケースを必要としています。

ありがとうございました。

答えて

3

あなたが唯一の特定のランクnのためのランク付けを行うために探しているので、私は希望すべての要素をソートするのではなく、各行で最も高いn個のランク付けされたエントリのソートされたインデックスだけを得るnp.argpartitionを提案する。これは、パフォーマンスの向上を目指しています。パフォーマンスのメリットについては、A fast way to find the largest N elements in an numpy arrayへの回答で詳しく説明していますので、ここでもそのメリットを享受してください。

このように、関数形式で、我々が持っているだろう -

def rank_df(df,rank): 
    coln = 'MAX' + str(rank) + '_NAMES' 
    sortID = np.argpartition(-df[['A','B','C','D']].values,rank,axis=1)[:,rank-1] 
    df[coln] = df.columns[sortID] 

をサンプル実行 -

In [84]: df 
Out[84]: 
      A   B   C   D 
0 -0.124851 0.152432 1.436602 -0.391178 
1 0.371932 1.732399 0.340876 -1.340609 
2 -1.218608 0.444246 0.169968 -1.437259 
3 -0.828132 0.821613 -0.556643 -0.407703 
4 -0.390477 0.048824 -2.087323 1.597030 

In [85]: rank_df(df,1) 

In [86]: rank_df(df,2) 

In [87]: df 
Out[87]: 
      A   B   C   D MAX1_NAMES MAX2_NAMES 
0 -0.124851 0.152432 1.436602 -0.391178   C   B 
1 0.371932 1.732399 0.340876 -1.340609   B   A 
2 -1.218608 0.444246 0.169968 -1.437259   B   C 
3 -0.828132 0.821613 -0.556643 -0.407703   B   D 
4 -0.390477 0.048824 -2.087323 1.597030   D   B 

ランタイムテスト

以前に記載されているように私はnp.argpartitionベースのアプローチのタイミングいますこのポストとnp.argsortは、まともなサイズのデータ​​フレームで@Psidomによって他のソリューションにリストされています。

In [92]: df = pd.DataFrame(np.random.randn(10000, 4), columns = list('ABCD')) 

In [93]: %timeit rank_df(df,2) 
100 loops, best of 3: 2.36 ms per loop 

In [94]: df = pd.DataFrame(np.random.randn(10000, 4), columns = list('ABCD')) 

In [95]: %timeit df['MAX2_NAMES'] = df.iloc[:,:4].apply(lambda r: r.index[r.argsort()[::-1][1]], axis = 1) 
1 loops, best of 3: 3.32 s per loop 
+0

非常にいいですが、私はスピードに関係なくどんな解決策も得られませんでしたが、数値的なソーティングパフォーマンスのヒントは便利です。 – ajsp

4

あなたは、インデックスを逆にし、第2の位置に1を拾う、行ごとargsort()を適用することができます。

df['MAX2_NAMES'] = df.iloc[:,:4].apply(lambda r: r.index[r.argsort()[::-1][1]], axis = 1) 

df 
#   A   B   C   D MAX1_NAMES MAX2_NAMES 
#0 -0.728424 -0.764682 -1.506795 0.722246    D   A 
#1 1.305500 -1.191558 0.068829 -1.244659   A   C 
#2 -0.175834 -0.140273 1.117114 0.817358    C   D 
#3 -0.255825 -1.534035 -0.591206 -0.352594   A   D 
#4 -2.408806 -1.925055 -1.797020 2.381936    D   C 
+0

素晴らしい、歓声。 – ajsp

関連する問題