如何高效计算DataFrame分组内对比值的对应排名?
高效计算Pandas分组内比较值的排名
我明白你现在的需求:给带有timestamp分组的DataFrame新增rank_c列,计算每个分组里compare值作为values一员时的排名。原来的循环写法虽然能跑,但数据量大的时候肯定慢得让人头疼,下面给你几个更高效的向量化实现方案,比循环快N倍!
先再明确下你的数据情况和期望结果:
原DataFrame示例
| timestamp | values | rank | compare |
|---|---|---|---|
| 12:00 | 0.23 | 1 | 0.42 |
| 12:00 | 0.45 | 3 | 0.42 |
| 12:00 | 0.37 | 2 | 0.42 |
| 14:00 | 0.33 | 2 | 0.22 |
| 14:00 | 0.54 | 3 | 0.22 |
| 14:00 | 0.17 | 1 | 0.22 |
| 14:00 | 0.76 | 4 | 0.22 |
期望输出(含rank_c列)
| timestamp | values | rank | compare | rank_c |
|---|---|---|---|---|
| 12:00 | 0.23 | 1 | 0.42 | 3 |
| 12:00 | 0.45 | 3 | 0.42 | 3 |
| 12:00 | 0.37 | 2 | 0.42 | 3 |
| 14:00 | 0.33 | 2 | 0.22 | 2 |
| 14:00 | 0.54 | 3 | 0.22 | 2 |
| 14:00 | 0.17 | 1 | 0.22 | 2 |
| 14:00 | 0.76 | 4 | 0.22 | 2 |
先看下你当前的循环实现(效率瓶颈所在)
import pandas as pd df_out = pd.DataFrame() for ts in df['timestamp'].unique(): df_help = df.loc[df['timestamp'] == ts] comp = df_help['compare'].iloc[0] value_list = list(df_help['values']) value_list.append(comp) value_list.sort() df_help['rank_c'] = value_list.index(comp) + 1 df_out = df_out.append(df_help, ignore_index = True)
这段代码的问题在于:循环遍历每个分组、手动拼接列表排序、用append拼接结果,这些都是Python层面的操作,完全没有利用Pandas的向量化优势,数据量越大越慢。
高效实现方案(两种可选)
方案一:基于分组统计的向量化实现(最通用,无需提前排序)
排名的本质很简单:compare的排名 = 分组内比它小的values的数量 + 1(因为最小值对应rank 1)。我们可以用groupby + transform直接实现,全程向量化:
import pandas as pd def get_rank_c(group): # 获取当前分组的compare值(同一分组内compare值一致) comp_val = group['compare'].iloc[0] # 统计分组内values小于comp_val的数量,加1得到排名 return (group['values'] < comp_val).sum() + 1 # 对timestamp分组,应用函数后直接赋值给rank_c列 df['rank_c'] = df.groupby('timestamp').transform(get_rank_c)['values']
方案二:利用searchsorted(适合分组内values已排序的场景)
如果你的每个分组内的values已经是排序好的(或者你可以提前排序),用searchsorted会更快,它能直接找到compare值在排序后列表中的插入位置,这个位置就是比它小的元素个数,加1就是排名:
def get_rank_c_sorted(group): comp_val = group['compare'].iloc[0] # 对当前分组的values排序 sorted_vals = group['values'].sort_values().values # 找到comp_val的插入位置,加1得到排名 return sorted_vals.searchsorted(comp_val, side='left') + 1 df['rank_c'] = df.groupby('timestamp').transform(get_rank_c_sorted)['values']
为什么这些方案更高效?
Pandas的groupby和transform都是基于底层的C语言实现的向量化操作,避开了Python循环的性能开销。当你的DataFrame有几万甚至几十万行时,这些方法的速度会比循环快几十倍甚至上百倍,而且代码更简洁易读。
内容的提问来源于stack exchange,提问作者Philipp
相关产品推荐
相关产品推荐

