Pandas groupby后nlargest性能优化及获取第二大值行的技术咨询
高效解决Pandas分组排序取前N行及指定行的问题
针对你遇到的apply方法处理大量分组时速度慢的问题,以及只取每组第二行的需求,这里给出两个高效的解决方案——都是基于Pandas的向量化操作,比逐组apply快得多:
一、替代apply快速获取每组前2行
apply慢的核心原因是它会对每个分组单独执行函数,在分组数量多的时候,循环开销极大。更高效的思路是先整体排序,再分组取头部——Pandas的sort_values和groupby.head都是经过优化的批量操作,性能提升非常明显:
# 先按Date保持原顺序,再按OI降序排序(确保每组内OI从大到小排列) df_sorted = df.sort_values(['Date', 'OI'], ascending=[True, False]) # 分组后取每组前2行,sort=False保留原数据的分组顺序 top2 = df_sorted.groupby('Date', sort=False).head(2)
这个方法的时间复杂度远低于apply,尤其是当分组数超过1000时,速度差距会非常显著。
二、仅获取每组按OI排序后的第二行
如果只需要每组的第二行(即降序排序后的第2个元素),推荐两种可靠的实现方式:
方法1:排序后用groupby.nth()
利用nth()直接提取分组内指定位置的行(索引从0开始,所以第二行对应nth(1)):
# 先按Date和OI降序排序 df_sorted = df.sort_values(['Date', 'OI'], ascending=[True, False]) # 取每组第二行,dropna=False可选,用于保留组内不足2行的分组(会返回NaN) second_row = df_sorted.groupby('Date', sort=False, dropna=False).nth(1)
方法2:用rank()标记排名后筛选
如果需要处理OI有重复值的场景,可以用rank()给每组内的OI标记排名,再筛选排名为2的行:
# 按Date分组,对OI降序排名,method='first'确保相同OI的行有唯一排名 df['oi_rank'] = df.groupby('Date')['OI'].rank(ascending=False, method='first') # 筛选排名为2的行,最后删除临时的排名列 second_row = df[df['oi_rank'] == 2].drop('oi_rank', axis=1)
如果业务允许相同OI的行共享排名,可以把method='first'换成method='min',但这种情况下可能会出现多行排名为2的情况,需要根据你的需求调整。
内容的提问来源于stack exchange,提问作者Z.G
相关产品推荐
相关产品推荐

