pandas中groupby的排名
我有一个典型的“面板数据”(在经济学术语中,而不是pandas的面板对象)。这个数据表里有一个 Date
列和一个 ID
列,还有其他一些列包含特定的数值。对于每个日期,我需要根据 V1 在不同的 ID 之间进行排名,把它们分成10组(十分位),并创建一个新的列叫 rank_col
(取值从1到10)来标识排名。然后,把所有的 rank1、rank2,...rank10 在时间上汇总,计算一些统计数据,比如平均值和标准差。
在SAS中,可以通过以下代码轻松实现这个目标,同时也说明了我的意图:
proc sort data=df;
by Date;
proc rank data=df out=df_ranked groups=10;
var V1;
ranks rank_col;
by Date;
run;
df_ranked
和 df
是一样的,只是多了一个叫 rank_col
的列,这个列包含了每一行所属的排名组。
抱歉我没有样本数据来展示结构,实际上需要一份长数据来说明。但SAS代码正好展示了我想要的结果。
谢谢你的帮助!
2 个回答
3
这样做可以更简单,不需要单独的foo
In [782]: df.groupby('Date')['V1'].transform(lambda x: pd.qcut(x, 10, labels=False))
Out[782]:
0 6
1 4
2 3
3 8
4 9
5 1
6 0
7 0
8 1
9 7
10 8
11 5
12 2
13 4
14 9
Name: V1, dtype: int64
把值赋给列
In [783]: df['ranks'] = df.groupby('Date')['V1'].transform(pd.qcut, 10, labels=False)
In [784]: df
Out[784]:
Date id V1 ranks
0 2013-01-01 1 10 6
1 2013-01-01 2 8 4
2 2013-01-01 3 6 3
3 2013-01-01 4 11 8
4 2013-01-01 5 13 9
5 2013-01-01 6 4 1
6 2013-01-01 7 2 0
7 2013-02-01 1 1 0
8 2013-02-01 2 3 1
9 2013-02-01 3 9 7
10 2013-02-01 4 11 8
11 2013-02-01 5 7 5
12 2013-02-01 6 4 2
13 2013-02-01 7 6 4
14 2013-02-01 8 14 9
具体细节
In [786]: df
Out[786]:
Date id V1
0 2013-01-01 1 10
1 2013-01-01 2 8
2 2013-01-01 3 6
3 2013-01-01 4 11
4 2013-01-01 5 13
5 2013-01-01 6 4
6 2013-01-01 7 2
7 2013-02-01 1 1
8 2013-02-01 2 3
9 2013-02-01 3 9
10 2013-02-01 4 11
11 2013-02-01 5 7
12 2013-02-01 6 4
13 2013-02-01 7 6
14 2013-02-01 8 14
8
我刚刚找到了一种方法:
def grouping(data):
dec=pd.qcut(data['V1'],10,labels=False)
data['ranks']=dec
return data
df_ranked=df.groupby('Date').apply(grouping)
这个方法假设 dec
能够保持每一行的正确位置。
如果你有更好的方法,或者发现这个方法有什么错误,请告诉我。
谢谢!
编辑:如果你做以下操作,你可以只返回一个新的 ranks
列:
>>> df
Date id V1
0 2013-01-01 1 10
1 2013-01-01 2 8
2 2013-01-01 3 6
3 2013-01-01 4 11
4 2013-01-01 5 13
5 2013-01-01 6 4
6 2013-01-01 7 2
7 2013-02-01 1 1
8 2013-02-01 2 3
9 2013-02-01 3 9
10 2013-02-01 4 11
11 2013-02-01 5 7
12 2013-02-01 6 4
13 2013-02-01 7 6
14 2013-02-01 8 14
>>> foo = lambda x: pd.Series(pd.qcut(x,10,labels=False),index=x.index)
>>> df['ranks'] = df.groupby('Date')['V1'].apply(foo)
>>> df
Date id V1 ranks
0 2013-01-01 1 10 6
1 2013-01-01 2 8 4
2 2013-01-01 3 6 3
3 2013-01-01 4 11 8
4 2013-01-01 5 13 9
5 2013-01-01 6 4 1
6 2013-01-01 7 2 0
7 2013-02-01 1 1 0
8 2013-02-01 2 3 1
9 2013-02-01 3 9 7
10 2013-02-01 4 11 8
11 2013-02-01 5 7 5
12 2013-02-01 6 4 2
13 2013-02-01 7 6 4
14 2013-02-01 8 14 9