Pandas 如何提取分组内累计值占比达X%的前N行数据
Pandas 分组按价值占比筛选最少记录实现方案
核心逻辑
利用分组累积求和计算价值占比,筛选出刚好达到覆盖阈值的最少行,不需要额外排序(原数据已按分组内Value降序排列)。
代码实现
可读性优先版本(推荐,性能更好)
import pandas as pd # 自定义覆盖阈值,示例为覆盖90%的分组总价值 COVERAGE_THRESHOLD = 0.9 # 计算每个分组的总价值 df['group_total'] = df.groupby('Group')['Value'].transform('sum') # 计算分组内逐行累积价值 df['cum_value'] = df.groupby('Group')['Value'].cumsum() # 计算累积价值占分组总价值的比例 df['cum_ratio'] = df['cum_value'] / df['group_total'] # 筛选满足阈值的行,额外保留刚好超过阈值的第一行(避免分组首行占比就超阈值时无返回的边界问题) filtered_df = df[ df['cum_ratio'].le(COVERAGE_THRESHOLD) | df.groupby('Group')['cum_ratio'].transform('idxmin').eq(df.index) ] # 可选:删除中间计算列 filtered_df = filtered_df.drop(columns=['group_total', 'cum_value', 'cum_ratio']) # 查看结果 # 1. 总符合要求的记录数 print(f"总最少记录数:{len(filtered_df)}") # 2. 每个分组对应的最少记录数 print(filtered_df.groupby('Group').size())
精简版本
import pandas as pd COVERAGE_THRESHOLD = 0.9 filtered_df = df[ df.groupby('Group')['Value'].apply( lambda x: (x.cumsum()/x.sum()).le(COVERAGE_THRESHOLD) | (x.cumsum()/x.sum()).idxmin() == x.index ) ]
注意事项
- 仅适用于分组内已经按
Value列降序排序的数据集,若未排序需要先执行df = df.sort_values(['Group', 'Value'], ascending=[True, False]) - 内置的边界处理逻辑会保证每个分组至少返回1条记录,不会出现分组筛选结果为空的情况
内容的提问来源于stack exchange,提问作者TOuyang
相关产品推荐
相关产品推荐

