python - 在 Pandas 中,SQL类似于窗口函数: 在 python Pandas Dataframe中,行号

  显示原文与译文双语对照的内容

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

  1. 按一个或者多个字段对数据表进行分区
  2. 对于每个分区,向它的每一行添加一个由一个或者多个它的他字段组成的,分析器指定升序或者降序。

比如:


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, Key2 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)))

我试图扩展这个想法以使用分区( 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)

但是当我这么做的时候,我得到了很多 NaNs 。

理想情况下,有一种简洁的方法来复制 sql ( 我已经找到了基于窗口的聚合。"。"。这是 Pandas的一个衬线)的窗口功能能力。

时间: 原作者:

你可以通过使用 groupby 两次和 rank 方法来实现这里目的:


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

使用min方法参数可以给出共享相同 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

因此,我们觉得应该有一种本机方法来完成这个任务。

原作者:

pandas.lib.fast_zip() 可以从 array 列表创建一个元组 array 。 可以使用这里函数创建元组序列,然后对它的排序:


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

原作者:
...