Pandas实现条件分组 限制每组antal总和不超过2500的方法
问题结论
这个需求属于带顺序约束的容量限制分组场景,没有可直接套用的pandas内置聚合/分组API实现纯一行流方案,但完全不需要写笨重的逐行DataFrame遍历逻辑,仅需一次轻量线性扫描生成分组标记,再配合pandas原生的groupby聚合就能实现,代码可读性和执行效率都很高。
实现逻辑说明
你的分组规则本质是:按sqm从大到小的顺序依次累加antal,只要累加值不超过2500就归为同一组,超过阈值就开启新组重新累加,组内记录sqm的最大值作为sqm_from、最小值作为sqm_to、antal求和作为组总套数即可。
具体实现代码
首先导入依赖、构造测试数据,注意先按sqm降序排序保证分组顺序正确:
import pandas as pd # 构造原始数据 df = pd.DataFrame({ 'sqm': [30,29,28,27,26,25,24,23,22,21,20,19,18], 'antal': [1254,982,1570,1219,1332,1183,1177,679,615,296,369,306,301] }).sort_values('sqm', ascending=False, ignore_index=True) # 配置分组阈值 MAX_SUM = 2500
接下来生成分组ID,这里仅遍历antal的数值序列,不操作DataFrame本身,性能极高:
group_col = [] current_total = 0 group_id = 0 for cnt in df['antal']: # 加当前值超过阈值就开新组 if current_total + cnt > MAX_SUM: group_id += 1 current_total = 0 current_total += cnt group_col.append(group_id) df['gid'] = group_col
最后按分组ID聚合得到结果:
result = df.groupby('gid', as_index=False).agg( sqm_from=('sqm', 'max'), sqm_to=('sqm', 'min'), antal=('antal', 'sum') ).drop(columns='gid')
补充说明
运行代码得到的结果和你给出的期望输出逻辑完全匹配(你给出的示例中24-25分组的antal值2371属于笔误,实际计算值为1183+1177=2360,其余分组结果完全一致)。
不用刻意追求完全不用循环的pandas“纯原生”实现,这类强顺序依赖的分组问题本来就需要一次线性扫描判断边界,只要循环操作的是纯Python数值、不是逐行操作DataFrame的行对象,性能完全可以满足要求,比硬套pandas API写晦涩的奇技淫巧可维护性高很多。
内容的提问来源于stack exchange,提问作者AnonX
相关产品推荐
相关产品推荐

