在pandas DataFrame中更快地对子组中的行进行排名的方法

32 投票
2 回答
63642 浏览
提问于 2025-05-01 09:09

我有一个 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,依此类推。

现在我通过以下方式来评估排名:

  1. 先按值进行排序。
df.sort('value', ascending = True, inplace=True)
  1. 创建一个排名函数(这个函数假设变量已经排好序)
def ranker(df):
    df['rank'] = np.arange(len(df)) + 1
    return df
  1. 分别在每个小组上应用这个排名函数:
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

撰写回答