You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas如何基于其他分类列对同一列多次groupby分组求和

更优实现方案

不需要逐类筛选再拼接,用规则映射+单次分组的方式即可实现,代码冗余度低,计算效率远高于多次筛选pd.concat的方案,后续调整分类规则只需要修改规则字典即可,不需要改动核心计算逻辑。


具体实现步骤

  1. 首先导入依赖、加载原始数据,把分类规则统一定义为字典格式:
import pandas as pd
import numpy as np

# 原始数据加载
df = pd.DataFrame(
    [
        ["id1",1,1.23],["id1",2,1.56],["id1",3,1.65],["id1",4,1.73],["id1",5,0.89],
        ["id2",1,1.07],["id2",2,1.38],["id2",3,0.94],["id2",4,0.72],["id2",5,1.37],
        ["id3",1,1.04],["id3",2,0.56],["id3",3,0.78],["id3",4,1.12],["id3",5,0.84]
    ],
    columns=["order_id", "otype", "score"]
)

# 统一定义分类规则,新增/修改分类直接改这个字典即可
class_rules = {
    "class1": {1,2,3},
    "class2": {4,5},
    "class3": {1,2,3,4,5},
    "class4": {2,3,5}
}
  1. 生成otype到分类的映射表,和原始数据合并后单次分组求和:
# 构建otype与分类的匹配关系
otype_unique = df["otype"].unique()
map_pairs = []
for cls_name, otype_collect in class_rules.items():
    valid_otype = [ot for ot in otype_unique if ot in otype_collect]
    map_pairs.extend([(ot, cls_name) for ot in valid_otype])
cls_map = pd.DataFrame(map_pairs, columns=["otype", "class_name"])

# 合并后直接分组聚合
merge_df = df.merge(cls_map, on="otype", how="left")
result = merge_df.groupby(
    ["order_id", "class_name"],
    as_index=False
)["score"].sum().rename(
    columns={"class_name": "otype", "score": "score_sum"}
)

结果说明

运行后得到的结果和预期完全一致,你示例中id1对应class1的4.4是保留1位小数的展示值,实际计算结果为1.23+1.56+1.65=4.44,需要对齐小数位的话加一句result["score_sum"] = result["score_sum"].round(1)即可。id1的输出如下:

order_id   otype  score_sum
0      id1  class1       4.44
1      id1  class2       2.62
2      id1  class3       7.06
3      id1  class4       4.10

方案优势

  • 仅做1次表合并、1次分组聚合,没有重复遍历全表的冗余计算,数据量越大性能优势越明显
  • 分类规则统一收敛在字典中维护,不需要为每个分类写重复的筛选、聚合、拼接代码
  • 逻辑一致性强,不会因为漏写某个分类的筛选逻辑导致结果缺失

如果处理百万行以上的超大数据集追求极致性能,可以用numpy向量化判断替代merge操作,核心逻辑如下:

res_list = []
otype_arr = df["otype"].values
score_arr = df["score"].values
order_arr = df["order_id"].values
for cls_name, otype_collect in class_rules.items():
    mask = np.isin(otype_arr, list(otype_collect))
    cls_res = pd.Series(score_arr[mask]).groupby(order_arr[mask]).sum()
    res_list.append(
        cls_res.rename("score_sum").reset_index().assign(otype=cls_name)
    )
result = pd.concat(res_list, ignore_index=True)[["order_id", "otype", "score_sum"]]

内容的提问来源于stack exchange,提问作者Jason Bourne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 21:57:22