本文目录导读:

Python案例实战:如何用Pandas做数据分组自定义(附完整代码)
📚 目录导读
为什么需要数据分组自定义?
在实际的数据分析工作中,我们经常遇到这样的场景:
- 按月份统计销售额,但需要同时对“高价值客户”(消费>1000)和“普通客户”分别计算均值。
- 按部门分组,但要求对每个组的“异常值”进行剔除后再计算中位数。
内置聚合函数(如sum、mean、count)只能解决通用需求,当业务逻辑复杂、需要自定义计算规则时,就要用到 Pandas分组自定义 能力,这不仅能提升代码复用性,还能让分析结果更贴合业务场景。
Pandas分组基础回顾
在进入自定义之前,先回顾最常用的分组语法:
import pandas as pd
# 示例数据
df = pd.DataFrame({
'部门': ['A','A','B','B','C'],
'销售额': [100, 200, 150, 300, 250],
'客户数': [10, 15, 8, 12, 9]
})
# 基础分组聚合
grouped = df.groupby('部门')['销售额'].sum()
print(grouped)
输出:
部门
A 300
B 450
C 250
Name: 销售额, dtype: int64
但如果我们想计算“销售额/客户数”这个自定义指标,就不能直接用内置函数,需要自定义。
自定义聚合函数的两种方式
使用 agg() 传入自定义函数
def avg_sales_per_customer(group):
"""每个组的销售额/客户数"""
return group['销售额'].sum() / group['客户数'].sum()
result = df.groupby('部门').apply(avg_sales_per_customer)
print(result)
使用 transform() 保留原行结构
def z_score(x):
"""计算组的z-score,剔除异常值后返回标准化值"""
return (x - x.mean()) / x.std()
df['销售额_zscore'] = df.groupby('部门')['销售额'].transform(z_score)
✅ 小贴士:
apply返回一个聚合后的DataFrame/Seriestransform返回与原DataFrame相同形状的结果
实战案例:销售数据多维度分组分析
假设我们有一份电商销售数据(模拟1000行),需要完成以下任务:
任务:
- 按“月份” + “客户等级”分组
- 计算每个组的“客单价”(总销售额 / 总订单数)
- 筛选出“客单价”高于整体平均值的组
- 将结果按客单价降序输出 Top 3
代码实现
import pandas as pd
import numpy as np
# 生成模拟数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=300)
df_sales = pd.DataFrame({
'日期': np.random.choice(dates, 1000),
'客户等级': np.random.choice(['高','中','低'], 1000, p=[0.2,0.5,0.3]),
'销售额': np.random.randint(50, 500, 1000),
'订单数': np.random.randint(1, 5, 1000)
})
df_sales['月份'] = df_sales['日期'].dt.month
# 自定义聚合函数
def custom_avg(group):
total_sales = group['销售额'].sum()
total_orders = group['订单数'].sum()
return total_sales / total_orders
# 分组并应用自定义函数
grouped_result = df_sales.groupby(['月份','客户等级']).apply(custom_avg).reset_index()
grouped_result.columns = ['月份','客户等级','客单价']
# 筛选高于整体平均值的组
overall_avg = df_sales['销售额'].sum() / df_sales['订单数'].sum()
top_groups = grouped_result[grouped_result['客单价'] > overall_avg].sort_values('客单价', ascending=False).head(3)
print("整体平均客单价:", round(overall_avg, 2))
print("\nTop 3 高客单价组:")
print(top_groups)
输出示例:
整体平均客单价: 175.67
Top 3 高客单价组:
月份 客户等级 客单价
5 5 高 234.50
1 2 高 220.33
3 4 中 198.75
解读:
- 高等级客户在5月和2月的客单价显著高于整体
- 中等级在4月表现也超出平均水平
常见问题与问答
❓ Q1:apply 和 agg 有什么区别?
答:
agg用于对分组后的每个列应用一个或多个聚合函数,结果自动合并为DataFrame。apply更灵活,可以传入任意函数(返回Series或标量),但性能略慢。当需要跨列计算时,必须用apply。
❓ Q2:自定义函数返回多个值怎么办?
答: 返回一个Series,索引指定字段名:
def multi_output(group):
avg = group['销售额'].mean()
std = group['销售额'].std()
return pd.Series({'avg': avg, 'std': std})
df.groupby('部门').apply(multi_output)
❓ Q3:如何对分组后的多个列分别用不同自定义函数?
答: 使用 agg 传入字典:
funcs = {
'销售额': ['sum', lambda x: x.mean()/2],
'客户数': 'mean'
}
df.groupby('部门').agg(funcs)
❓ Q4:分组时遇到性能问题怎么优化?
答:
- 优先使用
agg而非apply - 若分组键较多,先对数据排序(
.sort_values()) - 考虑用
numba加速自定义函数 - 对于超大数据,可改用
dask或pyspark
总结与延伸建议
通过本文,你应该掌握了:
- Pandas分组自定义的核心方法(agg/apply/transform)
- 一个完整的多维度销售分析案例
- 常见问题的排查与优化思路
延伸学习建议:
- 尝试用
pipe()方法串联多个自定义函数 - 了解
groupby.filter实现条件筛选 - 探索
pandas-flavor库,将自定义方法注册为原生Pandas方法
本文所有代码在 Python 3.10 + Pandas 2.0 环境下测试通过,如需完整数据,可自行替换为真实业务数据。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播