PANDAS中类似SQL的窗口函数:Python Pandas Dataframe中的行编号

All*_*enQ 31 python numpy dataframe pandas

我来自sql背景,我经常使用以下数据处理步骤:

  1. 通过一个或多个字段对数据表进行分区
  2. 对于每个分区,在每个行中添加一个rownumber,将行按一个或多个其他字段排序,分析人员指定升序或降序

EX:

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        
Run Code Online (Sandbox Code Playgroud)

我正在寻找如何做PANDAS相当于这个SQL窗口函数:

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
Run Code Online (Sandbox Code Playgroud)

我已经尝试了以下哪些我没有'分区'的地方工作:

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)))
Run Code Online (Sandbox Code Playgroud)

我试图扩展这个想法以使用分区(pandas中的组)但以下不起作用:

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)
Run Code Online (Sandbox Code Playgroud)

但是当我这样做时,我只是得到了很多NaN.

理想情况下,有一种简洁的方式来复制sql的窗口功能(我已经找到了基于窗口的聚合...这是熊猫中的一个内容)...有人可以与我分享最惯用的方式在PANDAS中有这样的行数?

Max*_*axU 36

你也可以使用sort_values(),groupby()最后cumcount() + 1:

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

收益率:

   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
Run Code Online (Sandbox Code Playgroud)

用熊猫0.18测试PS

  • @maxU,如果您在groupby排序之前应用sort_values()而不考虑'key1'。但是在原始窗口函数中,期望是在“ key1”的键空间内进行排序 (2认同)
  • 收到“ValueError:无法从重复轴重新索引”。有什么帮助吗? (2认同)
  • @MaxU我创建了这个 /sf/ask/3879535271/ 任何帮助将不胜感激 (2认同)

Gok*_*nan 16

使用 groupby.rank 函数。这是工作示例。

df = pd.DataFrame({'C1':['a', 'a', 'a', 'b', 'b'], 'C2': [1, 2, 3, 4, 5]})
df

C1 C2
a  1
a  2
a  3
b  4
b  5

df["RANK"] = df.groupby("C1")["C2"].rank(method="first", ascending=True)
df

C1 C2 RANK
a  1  1
a  2  2
a  3  3
b  4  1
b  5  2

Run Code Online (Sandbox Code Playgroud)

  • 如果您只需要单列进行 ORDER BY,而不是多列(这就是为什么接受的答案更加复杂),这是一个很好的解决方案。 (2认同)

And*_*den 14

您可以通过使用groupby两次rank方法来执行此操作:

In [11]: g = df.groupby('key1')
Run Code Online (Sandbox Code Playgroud)

使用min方法参数为同一RN提供共享相同data1的值:

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')
Run Code Online (Sandbox Code Playgroud)

然后将这些结果分组并添加与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
Run Code Online (Sandbox Code Playgroud)

感觉应该有一种本地方式来做到这一点(可能会有!...).

  • @AndyHayden要获得“row_number()”的行为,您应该传递“method='first'”,而不是“method='min'”(这会给您“rank()”行为)。 (2认同)

sus*_*mit 7

您可以一起使用transformRank这是一个示例

df = pd.DataFrame({'C1' : ['a','a','a','b','b'],
           'C2' : [1,2,3,4,5]})
df['Rank'] = df.groupby(by=['C1'])['C2'].transform(lambda x: x.rank())
df
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

看看熊猫排名方法了解更多信息

  • 这与 Pandas 中的类似 SQL 的窗口功能非常接近。也可以只传入 pandas Rank 函数,而不是将其包装在 lambda 中。`df.groupby(by=['C1'])['C2'].transform(pd.DataFrame.rank)` (2认同)