用agg配合lambda可实现字符串拼接分组,需显式astype(str)并dropna()处理空值,支持去重、取前N、加前缀等逻辑,多列不同聚合用字典传入最清晰。

用 agg 配合 lambda 实现字符串拼接
分组后想把非数值列(比如字符串、类别)合并成一个字符串,最直接的方式是用 groupby().agg() 配合 lambda。默认的 sum 或 mean 对字符串会报错,但 agg 允许你传任意函数。
常见错误是直接写 df.groupby('A')['B'].sum()——这在 pandas 1.5+ 会抛出 TypeError: unsupported operand type(s) for +: 'str' and 'int',因为 pandas 尝试把字符串当数字加了。
- 正确做法:用
.agg(lambda x: ' | '.join(x.astype(str))),显式转成字符串再拼 - 注意
x是Series,不是列表,所以不能直接用' | '.join(x)(会报TypeError: sequence item 0: expected str instance, got float) - 如果原始数据含
NaN,astype(str)会变成'nan';需要先用x.dropna()过滤
处理空值和重复值的拼接逻辑
真实数据里常有缺失或重复项,直接拼容易污染结果。比如用户标签列里多个 None 或重复的 'vip',拼出来就是 'vip | nan | vip'。
- 去重拼接:
.agg(lambda x: '、'.join(x.dropna().unique())) - 保留顺序去重(pandas 1.5+ 支持):
.agg(lambda x: '、'.join(pd.unique(x.dropna()))) - 只取前 3 个值避免字段过长:
.agg(lambda x: '、'.join(x.dropna().head(3).astype(str))) - 如果某组全为空,
join会返回空字符串,不会报错,但你要确认业务是否接受空结果
用 apply 替代 agg 的适用场景
当拼接逻辑更复杂(比如要加前缀、按条件过滤、调用外部函数),apply 比 agg 更灵活,因为它把整组 Series 当作参数传入,而不是逐列聚合。
立即学习“Python免费学习笔记(深入)”;
-
df.groupby('A')['B'].apply(lambda x: f"tags: {', '.join(x.dropna())}")可以加固定前缀 -
apply返回的是Series,索引是分组键;agg返回的是聚合后的值,类型取决于 lambda 返回值 - 性能上
agg通常更快,apply在逻辑复杂时更易读,别为了“看起来高级”硬套apply - 不要在
apply里写带副作用的操作(如修改原df),pandas 不保证执行顺序
多列不同拼接方式一次完成
实际中往往要对多列用不同规则拼:一列去重拼,一列取最大长度值,一列计数。这时用字典传给 agg 最干净。
- 写法:
df.groupby('group_col').agg({'col1': lambda x: ' | '.join(x.dropna().unique()), 'col2': 'count', 'col3': 'max'}) - 注意键名必须是列名,值可以是字符串(内置方法名)或函数对象;混用时别漏掉引号
- 如果某列参与分组又想聚合,得先
reset_index(drop=False)或用as_index=False,否则该列不在agg的列名范围内 - 返回结果列名会继承字典 key,不会自动加后缀;想区分原始列名可用命名元组,但多数情况没必要
真正容易被忽略的是空值处理粒度——dropna() 是按当前 Series 做的,不是全局;如果某组里只有 1 行且是 NaN,dropna() 后就空了,join 返回空字符串,这个边界情况得结合业务判断是否要补默认值。


















