61

私はSQLのバックグラウンドから来ており、次のデータ処理ステップを頻繁に使用しています。

  1. 1 つ以上のフィールドでデータのテーブルを分割する
  2. パーティションごとに、アナリストが昇順または降順を指定する 1 つ以上の他のフィールドによって行をランク付けする行番号を各行に追加します。

元:

df = pd.DataFrame({'key1' : ['a','a','a','b','a'],
           'data1' : [1,2,2,3,3],
           'data2' : [1,10,2,3,30]})
df
     data1        data2     key1    
0    1            1         a           
1    2            10        a        
2    2            2         a       
3    3            3         b       
4    3            30        a        

このSQLウィンドウ関数に相当するPANDASを実行する方法を探しています:

RN = ROW_NUMBER() OVER (PARTITION BY Key1 ORDER BY Data1 ASC, Data2 DESC)


    data1        data2     key1    RN
0    1            1         a       1    
1    2            10        a       2 
2    2            2         a       3
3    3            3         b       1
4    3            30        a       4

「パーティション」がない場所で動作するようになった次のことを試しました。

def row_number(frame,orderby_columns, orderby_direction,name):
    frame.sort_index(by = orderby_columns, ascending = orderby_direction, inplace = True)
    frame[name] = list(xrange(len(frame.index)))

このアイデアを拡張して、パーティション (パンダのグループ) を操作しようとしましたが、次の方法は機能しませんでした。

df1 = df.groupby('key1').apply(lambda t: t.sort_index(by=['data1', 'data2'], ascending=[True, False], inplace = True)).reset_index()

def nf(x):
    x['rn'] = list(xrange(len(x.index)))

df1['rn1'] = df1.groupby('key1').apply(nf)

しかし、これを行うと、多くの NaN が得られました。

理想的には、SQLのウィンドウ関数機能を複製する簡潔な方法があるでしょう(ウィンドウベースの集計を理解しました...これはパンダのワンライナーです)...誰かが私と最も慣用的な方法を共有できますかPANDAS でこのような行に番号を付けますか?

4

5 に答える 5

81

sort_values()を使用することもできgroupby()ますcumcount() + 1

df['RN'] = df.sort_values(['data1','data2'], ascending=[True,False]) \
             .groupby(['key1']) \
             .cumcount() + 1
print(df)

収量:

   data1  data2 key1  RN
0      1      1    a   1
1      2     10    a   2
2      2      2    a   3
3      3      3    b   1
4      3     30    a   4

Pandas 0.18 で PS テスト済み

于 2016-04-18T21:18:39.583 に答える
22

メソッドgroupbyと一緒に 2 回使用することで、これを行うことができます。rank

In [11]: g = df.groupby('key1')

min メソッド引数を使用して、同じ data1 を共有する値に同じ RN を指定します。

In [12]: g['data1'].rank(method='min')
Out[12]:
0    1
1    2
2    2
3    1
4    4
dtype: float64

In [13]: df['RN'] = g['data1'].rank(method='min')

次に、これらの結果をグループ化して、data2 に関するランクを追加します。

In [14]: g1 = df.groupby(['key1', 'RN'])

In [15]: g1['data2'].rank(ascending=False) - 1
Out[15]:
0    0
1    0
2    1
3    0
4    0
dtype: float64

In [16]: df['RN'] += g1['data2'].rank(ascending=False) - 1

In [17]: df
Out[17]:
   data1  data2 key1  RN
0      1      1    a   1
1      2     10    a   2
2      2      2    a   3
3      3      3    b   1
4      3     30    a   4

これを行うためのネイティブな方法が必要なように感じます (あるかもしれません!...)。

于 2013-07-21T21:24:07.373 に答える
0

pandas.lib.fast_zip()配列のリストからタプル配列を作成できます。この関数を使用してタプル シリーズを作成し、ランク付けできます。

values = {'key1' : ['a','a','a','b','a','b'],
          'data1' : [1,2,2,3,3,3],
          'data2' : [1,10,2,3,30,20]}

df = pd.DataFrame(values, index=list("abcdef"))

def rank_multi_columns(df, cols, **kw):
    data = []
    for col in cols:
        if col.startswith("-"):
            flag = -1
            col = col[1:]
        else:
            flag = 1
        data.append(flag*df[col])
    values = pd.lib.fast_zip(data)
    s = pd.Series(values, index=df.index)
    return s.rank(**kw)

rank = df.groupby("key1").apply(lambda df:rank_multi_columns(df, ["data1", "-data2"]))

print rank

結果:

a    1
b    2
c    3
d    2
e    4
f    1
dtype: float64
于 2013-07-22T03:14:01.217 に答える