在pandas DataFrame中更快地对子组中的行进行排名的方法
我有一个 pandas 数据框,里面包含了不同的小组。
df = pd.DataFrame({
'id':[1, 2, 3, 4, 5, 6, 7, 8],
'group':['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b'],
'value':[.01, .4, .2, .3, .11, .21, .4, .01]
})
我想要找出每个 ID 在它所属小组中的排名,假设值越小排名越好。在上面的例子中,在 A 组中,ID 1 的排名是 1,ID 2 的排名是 4。在 B 组中,ID 5 的排名是 2,ID 8 的排名是 1,依此类推。
现在我通过以下方式来评估排名:
- 先按值进行排序。
df.sort('value', ascending = True, inplace=True)
- 创建一个排名函数(这个函数假设变量已经排好序)
def ranker(df):
df['rank'] = np.arange(len(df)) + 1
return df
- 分别在每个小组上应用这个排名函数:
df = df.groupby(['group']).apply(ranker)
这个过程是可行的,但当我处理数百万行数据时,速度真的很慢。有没有人有什么想法可以让排名函数更快一些?
2 个回答
15
在处理一个很大的数据表(有1300万行数据)时,使用带分组的排名方法让我电脑的8GB内存用尽了,而且花了很长时间。我找到了一种对内存要求更低的解决办法,放在这里以备不时之需:
df.sort_values('value')
tmp = df.groupby('group').size()
rank = tmp.map(range)
rank =[item for sublist in rank for item in sublist]
df['rank'] = rank
52
这个rank功能是用Cython优化过的,所以运行起来会非常快。而且你可以使用和df.rank()
一样的选项。这里有关于rank
的文档。你可以看到,处理相同值(也就是平局)的方式有五种不同的选择,可以通过method
这个参数来设置。
另外,你可能只是想要这个组的.cumcount()
。
In [12]: df.groupby('group')['value'].rank(ascending=False)
Out[12]:
0 4
1 1
2 3
3 2
4 3
5 2
6 1
7 4
dtype: float64