Python案例详解如何用Pandas做数据分组合并
📖 目录导读
- 数据分组合并的核心概念
- 准备工作:环境搭建与数据构造
- 单列分组+聚合函数合并
- 多列分组+自定义合并逻辑
- 分组后横向合并(拼接列)
- 分组内纵向合并(拼接行)
- 常见问题与优化技巧
- Q&A 实战问答
数据分组合并的核心概念
在数据分析中,我们经常需要将数据按某个类别分组,再对组内数据进行汇总或合并,Pandas提供了groupby()与merge()/concat()的灵活组合,实现“先拆分,再合并”的场景。

为什么需要分组合并?
- 按地区汇总销售数据后,再与地区信息表合并
- 按用户分组后,将同一用户的多条行为记录合并为一条序列
- 分组计算统计指标后,再横向附加到原始数据
准备工作:环境搭建与数据构造
import pandas as pd
import numpy as np
# 创建示例数据:销售订单表
orders = pd.DataFrame({
'order_id': ['A01','A02','A03','A04','A05'],
'customer_id': ['C1','C1','C2','C3','C2'],
'product': ['手机','耳机','充电器','手机','耳机'],
'amount': [5000, 200, 150, 4800, 250],
'date': ['2024-01-01','2024-01-02','2024-01-01','2024-01-03','2024-01-02']
})
# 客户信息表
customers = pd.DataFrame({
'customer_id': ['C1','C2','C3'],
'city': ['北京','上海','广州'],
'level': ['VIP','普通','普通']
})
print(orders)
print(customers)
案例一:单列分组+聚合函数合并
需求:按customer_id分组,计算每个客户的消费总额,再合并客户城市信息。
# 第一步:分组聚合
customer_amount = orders.groupby('customer_id')['amount'].sum().reset_index()
customer_amount.columns = ['customer_id', 'total_amount']
# 第二步:合并客户信息
result = pd.merge(customer_amount, customers, on='customer_id', how='left')
print(result)
输出: | customer_id | total_amount | city | level | |-------------|--------------|------|-------| | C1 | 5200 | 北京 | VIP | | C2 | 400 | 上海 | 普通 | | C3 | 4800 | 广州 | 普通 |
💡 技巧:
reset_index()将分组键变回列,方便后续合并。
案例二:多列分组+自定义合并逻辑
需求:按customer_id和date分组,将同一客户同一天的多个商品合并为一条字符串。
# 自定义合并函数:将产品名用逗号连接
def merge_products(series):
return '、'.join(series)
grouped = orders.groupby(['customer_id', 'date']).agg({
'product': merge_products,
'amount': 'sum'
}).reset_index()
print(grouped)
输出: | customer_id | date | product | amount | |-------------|------------|--------------|--------| | C1 | 2024-01-01 | 手机 | 5000 | | C1 | 2024-01-02 | 耳机 | 200 | | C2 | 2024-01-01 | 充电器 | 150 | | C2 | 2024-01-02 | 耳机 | 250 | | C3 | 2024-01-03 | 手机 | 4800 |
案例三:分组后横向合并(拼接列)
需求:将分组统计的指标(如均值、总和)作为新列拼接到原始数据中。
# 计算每个客户的消费均值
mean_amount = orders.groupby('customer_id')['amount'].transform('mean')
# 直接作为新列加入
orders['customer_avg'] = mean_amount
print(orders[['order_id','customer_id','amount','customer_avg']])
🔑 注意:
transform()保留原始行数,是横向合并的快捷方法。
案例四:分组内纵向合并(拼接行)
需求:按产品类别分组,将每个组内的所有订单记录合并为一个DataFrame子集,再导出为独立文件。
for product_name, group_df in orders.groupby('product'):
# 对每个组内数据可以进一步处理或保存
print(f"产品:{product_name},订单数:{len(group_df)}")
# group_df.to_csv(f'{product_name}_orders.csv', index=False)
常见问题与优化技巧
| 问题 | 解决 |
|---|---|
| 分组后索引混乱 | 使用reset_index(drop=True)重置 |
| 合并后列名冲突 | 添加suffixes=('_left','_right')参数 |
| 大数据量分组慢 | 使用categorical dtype对分组列优化 |
| 需要保留分组键 | 确保groupby(..., as_index=False) |
代码优化示例:
# 优化分组列数据类型
orders['customer_id'] = orders['customer_id'].astype('category')
# 分组时避免生成分层索引
result = orders.groupby('customer_id', as_index=False)['amount'].sum()
Q&A 实战问答
Q1: groupby之后如何同时合并多个统计指标?
A: 使用agg()字典参数:
orders.groupby('customer_id').agg({
'amount': ['sum','mean','count'],
'product': lambda x: list(x)
})
Q2: 分组合并后数据行数为什么变少?
A: groupby().agg()默认会压缩数据,每一组只保留一行,若需保持原行数,使用transform()。
Q3: 如何按条件分组后再合并外部表?
A: 先用布尔索引筛选数据,再分组合并:
filtered = orders[orders['amount'] > 200]
grouped = filtered.groupby('customer_id')['amount'].sum().reset_index()
final = pd.merge(grouped, customers, on='customer_id')
Q4: 三个DataFrame如何实现分组嵌套合并?
A: 分步处理,先合并前两个,再合并第三个:
step1 = orders.groupby('customer_id').agg(...).reset_index()
step2 = pd.merge(step1, customers, on='customer_id')
final = pd.merge(step2, products_info, left_on='product', right_on='product_id')
通过以上四个案例,您已掌握Pandas数据分组合并的核心技巧,从最简单的聚合统计到自定义合并逻辑,再到性能优化,这些方法足够应对90%以上的数据分析需求,建议在实际项目中先画出数据关系图,再选择最合适的合并方式。