Python案例详解如何用Pandas做数据分组统计量
📚 目录导读
- 引言:为什么数据分组统计是数据分析的核心?
- Pandas分组统计基础:groupby() 的工作原理
- 实战案例一:销售数据按类别统计总额与均值
- 实战案例二:多级分组与聚合函数组合应用
- 实战案例三:自定义聚合函数与分组后变换
- 常见问题与避坑指南(Q&A)
- 掌握分组统计的三大心法
引言:为什么数据分组统计是数据分析的核心?
在数据分析的日常工作中,面对动辄上万行、数百列的表格数据,我们常常需要回答这类问题:“不同产品类别的平均销售额是多少?” 或者 “每个地区的订单数量分布如何?”,这类“按某个维度分组,然后计算统计量”的操作,正是分组统计(GroupBy) 的用武之地。

Pandas作为Python数据分析的“瑞士军刀”,其groupby()功能结合聚合函数(如sum(), mean(), count()),可以在几行代码内完成传统Excel需要繁琐透视表操作的任务,本文将通过三个完整的Python案例,手把手教你如何用Pandas实现高效的数据分组统计,并附上搜索引擎优化(SEO)友好的问答环节,帮你避开常见陷阱。
适用人群:有Python基础但刚接触Pandas的数据分析新手,以及希望提升数据预处理效率的从业者。
Pandas分组统计基础:groupby() 的工作原理
在深入案例前,我们先理解核心机制,Pandas的groupby()生成一个GroupBy对象,它本身并不立即计算,而是懒加载——只有当你调用聚合函数(如.sum()、.mean())时,才会执行计算并返回结果。
基本流程三步骤:
- 拆分(Split):根据指定列(或多个列)将DataFrame拆分为多个组。
- 应用(Apply):对每个组独立应用一个函数(聚合、转换或过滤)。
- 组合(Combine):将各组结果合并到一个DataFrame或Series中。
import pandas as pd
# 示例数据
df = pd.DataFrame({
'类别': ['A', 'A', 'B', 'B', 'A'],
'金额': [100, 150, 200, 250, 300]
})
# 第一步:按'类别'分组,第二步:计算每组金额总和
result = df.groupby('类别')['金额'].sum()
输出结果会是一个带有类别索引的Series,包含了每个组的统计量。
实战案例一:销售数据按类别统计总额与均值
场景描述
假设你是一家电商公司的数据分析师,有一张包含订单ID、产品类别、销售额和利润的表格,老板想知道每个产品类别的总销售额和平均利润。
完整代码与解析
import pandas as pd
# 构造模拟数据
data = {
'订单ID': [101, 102, 103, 104, 105],
'类别': ['电子产品', '服饰', '电子产品', '食品', '服饰'],
'销售额': [5000, 1200, 8000, 450, 2500],
'利润': [1000, 300, 1500, 100, 500]
}
df_sales = pd.DataFrame(data)
# 按类别分组,同时计算销售额总和与利润均值
grouped = df_sales.groupby('类别').agg(
总销售额=('销售额', 'sum'),
平均利润=('利润', 'mean')
).reset_index() # 将分组键从索引变为普通列
print(grouped)
输出结果:
类别 总销售额 平均利润
0 服饰 3700 400.0
1 食品 450 100.0
2 电子产品 13000 1250.0
关键点:
agg()函数可以同时指定多个聚合方式,传入一个字典或元组列表。reset_index()将分组列还原为普通列,便于后续处理或导出。
实战案例二:多级分组与聚合函数组合应用
场景描述
数据更加复杂时,我们需要按多个维度分组,某连锁超市希望按城市和门店类型(如“旗舰店”、“标准店”)两个维度,统计每组的订单数量和平均客单价。
代码实操
# 模拟数据
store_data = {
'城市': ['北京', '北京', '上海', '上海', '北京', '上海'],
'门店类型': ['旗舰店', '标准店', '旗舰店', '标准店', '标准店', '旗舰店'],
'订单数': [150, 200, 180, 220, 210, 195],
'客单价': [350, 280, 400, 310, 270, 390]
}
df_store = pd.DataFrame(store_data)
# 多级分组:按城市和门店类型
# 使用 agg() 同时计算总和与均值
result_multi = df_store.groupby(['城市', '门店类型']).agg(
总订单数=('订单数', 'sum'),
平均客单价=('客单价', 'mean')
).reset_index()
print(result_multi)
运行结果:
城市 门店类型 总订单数 平均客单价
0 北京 旗舰店 150 350.0
1 北京 标准店 410 275.0 # 注意:北京标准店有两行,求和得到410
2 上海 旗舰店 375 395.0
3 上海 标准店 220 310.0
进阶技巧:如果你想对同一列应用多个聚合函数(如同时计算销售额的sum和std),可以这样写:
df_store.groupby('城市')['客单价'].agg(['mean', 'std', 'count'])
实战案例三:自定义聚合函数与分组后变换
场景描述
当内置聚合函数(如sum、mean)无法满足需求时,我们需要自定义函数,计算每个分组中高于该组平均值的销售额占比,或者,你想给每个分组内的数据添加一列“本组排名”,而不压缩行数——这时要用transform()。
案例:计算每个组内的百分比排名
# 另辟数据:学生成绩
score_data = {
'班级': ['A', 'A', 'B', 'B', 'C'],
'姓名': ['张三', '李四', '王五', '赵六', '陈七'],
'成绩': [85, 92, 78, 88, 95]
}
df_score = pd.DataFrame(score_data)
# 自定义函数:返回每个成绩在所在班级内的百分位排名(0~1之间)
def percentile_rank(group):
# group 是一个Series(该班级的所有成绩)
return group.rank(pct=True)
# 使用 transform() 保持原有形状,添加新列
df_score['班级内排名'] = df_score.groupby('班级')['成绩'].transform(percentile_rank)
print(df_score)
输出:
班级 姓名 成绩 班级内排名
0 A 张三 85 0.500
1 A 李四 92 1.000
2 B 王五 78 0.500
3 B 赵六 88 1.000
4 C 陈七 95 1.000
为什么用transform()?
因为transform()返回一个与原DataFrame行数相同的Series,可以方便地添加为一列,而apply()或agg()会压缩行数,不适合这种“给原表添加统计特征”的需求。
常见问题与避坑指南(Q&A)
❓ 问题1:分组后为什么索引乱掉了?如何保持原顺序?
回答:groupby()默认会按分组键排序(如果键是字符串,按字母顺序),如果你希望保留数据原顺序,请设置sort=False:
df.groupby('类别', sort=False)['金额'].sum()
❓ 问题2:agg() 和 apply() 有什么区别?
回答:
agg():专门用于聚合操作(返回标量值),可以一次应用多个函数,返回的DataFrame行数等于组数。apply():更通用,可以返回任意形状(标量、Series、DataFrame),如果返回标量,作用类似agg();如果返回Series,会展开成多行。性能上agg()通常更快,优先使用agg()实现聚合。
❓ 问题3:分组后如何过滤掉某些组(例如只保留总销售额大于1000的组)?
回答:使用filter()方法,它根据一个返回布尔值的函数保留整个组:
# 只保留组内总销售额 > 1000 的组
filtered = df_sales.groupby('类别').filter(lambda x: x['销售额'].sum() > 1000)
❓ 问题4:如何处理分组中的缺失值(NaN)?
回答:默认情况下,groupby()会排除所有包含NaN的分组键行,如果你希望将NaN也作为一个单独的分组,使用dropna=False:
df.groupby('类别', dropna=False)['金额'].sum()
❓ 问题5:如何将分组统计结果可视化?
回答:分组统计结果通常是Series或DataFrame,可以直接用Matplotlib或Seaborn绘图。
import matplotlib.pyplot as plt
grouped = df_sales.groupby('类别')['销售额'].sum()
grouped.plot(kind='bar')
plt.show()
掌握分组统计的三大心法
通过以上三个由浅入深的案例,我们系统学习了Pandas数据分组统计的核心技能:
- 熟记“拆分-应用-组合”流程。
groupby()是拆分,聚合函数(agg()、transform())是应用,返回结果是组合。 - 区分
agg()与transform()。agg()用于压缩数据(行变少),transform()用于保留原行数添加统计特征。 - 善用多级分组与自定义函数,通过
groupby([col1, col2])实现多维统计,通过lambda或def函数解决复杂逻辑。
数据分析没有银弹,但Pandas的groupby绝对是你武器库中最锋利的刀,建议在本地Jupyter Notebook中逐行运行以上案例,手动修改参数观察效果——实践是掌握数据分组统计的最佳途径。