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

Pandas:按ID1去重后基于ID2聚合val均值求和的实现

Pandas分组聚合问题:按ID1去重后对均值求和

原始数据

创建DataFrame的代码:

import pandas as pd
import numpy as np
data = pd.DataFrame({"ID1": ["a", "a", "a", "b", "b", "b", "c", "c", "c"],
                     "ID2": ["k", "k", "k", "k","k", "k", "j", "j", "j"],
                     "val": [18, 19, 20, 18, 19, 20, 34, 35, 37]
                     })

输出的DataFrame:

ID1 ID2  val
0    a   k   18
1    a   k   19
2    a   k   20
3    b   k   18
4    b   k   19
5    b   k   20
6    c   j   34
7    c   j   35
8    c   j   37

需求说明

先按ID1分组计算val列的均值,再按ID2分组对该均值求和,同时统计每个ID2对应的唯一ID1数量(命名为Volume)。

原实现问题

原代码:

(data
 .assign(val_id1_avg = data.groupby("ID1")["val"].transform("mean"))
 .groupby("ID2")
 .agg(val_avg = ("val_id1_avg", lambda x: np.sum(x.unique())),
      volume=("ID1", 'nunique'))
 .reset_index())

原输出:

ID2   val_avg  volume
0    j  35.333333       1
1    k  19.000000       2

错误原因:对于ID2=k,ID1=a和ID1=b的val均值都是19,x.unique()会去重为单个19,导致求和结果仅为19,而实际需要的是两个ID1的均值之和(19+19=38)。

正确实现方法

方法一:分步处理(清晰直观)

# 1. 计算每个ID1对应的val均值
id1_avg = data.groupby("ID1")["val"].mean().reset_index(name="val_id1_avg")
# 2. 关联原数据的ID1和ID2,仅保留必要列
merged_data = data[["ID1", "ID2"]].merge(id1_avg, on="ID1")
# 3. 按ID1和ID2去重,确保每个ID1在同一ID2下只出现一次
unique_records = merged_data.drop_duplicates(subset=["ID1", "ID2"])
# 4. 按ID2分组,求和均值并统计唯一ID1数量
final_result = unique_records.groupby("ID2").agg(
    val_avg=("val_id1_avg", "sum"),
    Volume=("ID1", "nunique")
).reset_index()
# 格式化val_avg为两位小数
final_result["val_avg"] = final_result["val_avg"].round(2)
print(final_result)

输出结果:

ID2  val_avg  Volume
0   j    35.33       1
1   k    38.00       2

方法二:链式操作(简洁高效)

final_result = (data
                # 先计算每个ID1的val均值,添加为新列
                .assign(val_id1_avg=lambda df: df.groupby("ID1")["val"].transform("mean"))
                # 按ID1和ID2去重,避免同一ID1在同一ID2下重复计算
                .drop_duplicates(subset=["ID1", "ID2"])
                # 按ID2分组聚合
                .groupby("ID2")
                .agg(
                    val_avg=("val_id1_avg", "sum"),
                    Volume=("ID1", "nunique")
                )
                .reset_index()
                # 保留两位小数
                .round({"val_avg": 2})
)
print(final_result)

此方法与分步处理结果完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 23:47:35