Python实战案例:如何用Pandas高效完成数据分组与聚合分析
文章导读目录
- 为什么需要数据分组聚合?
- Pandas分组聚合核心函数:
groupby()入门 - 销售数据按“城市”分组求总销售额
- 多级分组与自定义聚合函数(apply/agg)
- 分组后保留原始数据的“复合操作”
- 常见错误与性能优化技巧
- SEO友好问答:新手最常问的5个问题
- 总结与下一步学习建议
为什么需要数据分组聚合?
在数据分析工作中,我们经常遇到这样的需求:“按城市统计每月的总销售额”、“按部门计算员工的平均薪资”、“按产品类别找出库存最少的10个SKU”——这些操作本质都是 “分割-应用-组合” 的流程,Pandas中的groupby机制正是为此设计,它允许你:

- 根据某列(或多列)的值将数据分成多个组;
- 对每个组独立应用函数(求和、均值、计数、自定义逻辑);
- 将结果合并成一个新的DataFrame。
根据Seo技术社区的案例统计,90%的Pandas数据分析任务都会用到分组聚合,掌握这一技能,能让你处理10万行以上的数据集时,将代码从20行缩减到3行。
Pandas分组聚合核心函数:groupby() 入门
基本语法
df.groupby('列名')['待运算列'].聚合函数()
groupby('列名'):定义分组依据(可以是字符串或列表);['待运算列']:指定要进行聚合计算的列(可选,如果省略则对所有数字列操作);.sum()/.mean()/.count()/.agg():聚合方式。
关键差异:.agg() vs .apply()
.agg():专注预定义聚合(sum,mean,np.std等),速度快,且对多列可指定不同函数;.apply():更灵活,可传入自定义函数操作整个分组DataFrame,但性能略低。
销售数据按“城市”分组求总销售额
场景
有一份销售数据表(sales.csv),包含 城市、销售员、产品、销售额、日期 等字段,需要按城市汇总总销售额。
实现代码
import pandas as pd
# 读取数据
df = pd.read_csv('sales.csv')
# 分组聚合:按城市,对销售额求和
city_sales = df.groupby('城市')['销售额'].sum()
print(city_sales)
实际输出示例
城市
上海 125000
北京 98000
广州 72000
Name: 销售额, dtype: int64
拓展:同时查看多个聚合指标
city_stats = df.groupby('城市')['销售额'].agg(['sum', 'mean', 'count'])
print(city_stats)
此时会得到每个城市的总销售额、平均单笔销售额和订单数量——这是企业销售周报的常见统计维度。
多级分组与自定义聚合函数
需求
需要同时按 城市 和 季度 分组,并且计算每个组的加权平均利润率(假设有 销售额 和 利润 两列)。
多级分组
# 按两个列分组 grouped = df.groupby(['城市', '季度']) # 多级聚合 result = grouped[['销售额', '利润']].sum()
此时索引成了MultiIndex(城市、季度),可以通过 .loc['上海':'北京'] 或 xs() 切片访问。
自定义聚合函数(使用lambda或def)
# 自定义加权平均(假设利润率 = 利润/销售额)
def weighted_margin(group):
return group['利润'].sum() / group['销售额'].sum()
margin_result = df.groupby('城市').apply(weighted_margin)
margin_result.name = '加权利润率'
注意:apply返回的是Series,适用于每个分组返回单个值的情形,如果需要按组处理后再拼接回原数据,使用.transform或.filter。
分组后保留原始数据的“复合操作”
有时候我们不希望仅仅得到一个汇总表,而是想保留原始行,同时增加分组统计列(给每一行标记该产品类别的平均价格)。
使用transform
# 计算每个产品类别下,该行的价格与类别平均价的差值
df['类别平均价'] = df.groupby('产品类别')['价格'].transform('mean')
df['价格差异'] = df['价格'] - df['类别平均价']
transform不会减少行数,只是将聚合结果广播回每一行——这在做异常值检测或相对排名时非常有用。
常见错误与性能优化技巧
容易踩的坑
- 忘记
.reset_index():groupby默认以分组列为索引,如果后续需要列名索引,记得调用.reset_index(); - 多级GroupBy后直接赋值:
df.groupby('A')['B'].sum() = something会报错,必须通过.transform实现; - 数据中存在NaN:分组键如果有NaN,该组会被自动忽略,可先
df.dropna(subset=['分组列'])。
性能提升小贴士
- 尽量使用
.agg()而非.apply(),尤其是大数据集; - 对groupby的列先排序(
sort=True),能减少分组时的计算开销; - 如果只需要部分列聚合,显式指定
['销售额']而非整个DataFrame。
SEO友好问答:新手最常问的5个问题
Q1:groupby和pivot_table有什么区别?
A:pivot_table底层也依赖groupby,但会自动生成行、列索引和数据透视格式,更美观;而groupby更灵活,适合编程处理。
Q2:如何对分组后的结果进行排序?
A:在groupby后接.agg(...).sort_values('列名', ascending=False)即可。
Q3:为什么我的groupby返回的是Series而不是DataFrame?
A:当你用['某列']指定单列后,聚合会返回Series,如果需要DataFrame,用两层方括号:[['某列']]。
Q4:可以同时对字符串列和数值列分组吗?
A:可以,字符串列分组时,相同内容的行被划分为一组,数值列则分桶(需要先通过pd.cut或pd.qcut分箱)。
Q5:多列groupby后,如何选择某个组?
A:使用.get_group(('组值1', '组值2'))方法,例如grouped.get_group(('上海', 'Q1'))。
总结与下一步学习建议
通过以上案例,你已经掌握了Pandas分组聚合的核心场景:单列/多列求和、自定义指标计算、数据转换保留(transform)、以及性能避坑。实际工作中,80%的数据看板指标都可以通过组合.groupby() + .agg()来完成。
建议你下一步:
- 尝试在真实数据集(如Kaggle的Titanic或零售销售)上练习多级分组和聚合;
- 阅读Pandas官方文档中关于
.resample()(时间序列分组)的内容; - 学习如何使用
pd.Grouper处理更复杂的分组逻辑(如按周分组、按自定义区间分组)。
数据分析的本质是“告别手动,用代码让机器自动分身做事”——Pandas的groupby正是你手中最锋利的刀。