Python案例如何用Pandas做数据分组业务

wen python案例 2

Python案例:如何用Pandas做数据分组业务?从入门到实战的完整指南

目录导读

  1. 数据分组业务的核心价值:为什么需要分组?案例场景一览
  2. Pandas分组基础:groupby()的语法与原理
  3. 实战案例一:销售数据按地区/月份分组统计
  4. 实战案例二:用户行为按付费等级分组分析
  5. 分组后的聚合运算进阶:agg()、transform()、filter()详解
  6. 常见错误与性能优化:多键分组、内存管理与dtype陷阱
  7. Q&A问答集锦:针对高频业务问题的代码级解答

数据分组业务的核心价值

在数据分析或业务运营中,“分组”是最基础也是最高频的操作。

Python案例如何用Pandas做数据分组业务

  • 电商需统计每个品类的月销售额、毛利率;
  • 运营需要按用户注册渠道对比留存率;
  • 财务要查看季度维度的成本波动;

如果不掌握分组聚合,你可能会陷入“手动写循环十万行数据”或者“用Excel透视表折腾到崩溃”的窘境,而Pandas的groupby()正是解决这类问题的利器。

场景速览:我们有一份包含“订单时间、客户ID、订单金额、商品类别、地区”的200万条模拟销售记录,业务要求:按“地区+月份”汇总总销售额、平均订单金额、本月交易客户数,如何用3行代码搞定?


Pandas分组基础:groupby()的语法与原理

核心语法:

df.groupby(by, axis=0, level=None, as_index=True, sort=True, group_keys=True)
  • by:分组依据,可以是列名、多列列表、Series或自定义函数。
  • as_index:默认True,分组列会成为索引;设为False可保留为普通列,便于后续merge。

工作原理:

Pandas的groupby延迟计算的——它只生成一个DataFrameGroupBy对象,不执行任何聚合操作,直到你调用mean(), sum(), count(), agg()等方法时,才会实际拆分-应用-组合。

快速测试(数据示例):
import pandas as pd
df = pd.DataFrame({
    '地区':['华东','华北','华东','华北'],
    '月份':[1,1,2,2],
    '销售额':[100,150,200,120]
})
# 简单分组求和
result = df.groupby('地区')['销售额'].sum()
print(result)

输出:

地区
华东    300
华北    270
Name: 销售额, dtype: int64

实战案例一:销售数据按地区+月份分组统计

原始数据结构(模拟):

订单ID 日期 客户ID 金额 商品类别 地区
001 2024-01-05 A100 299 电子 华东
002 2024-01-12 B201 89 服装 华北

业务需求:

生成一张报表,字段包含:地区, 月份, 总销售额, 平均订单金额, 交易客户数

代码实现:

import pandas as pd
# 1. 读取数据(假设已清洗)
df = pd.read_csv('sales_data.csv', parse_dates=['日期'])
# 2. 提取月份
df['月份'] = df['日期'].dt.month
# 3. 核心分组聚合
result = df.groupby(['地区', '月份'], as_index=False).agg(
    总销售额=('金额', 'sum'),
    平均订单金额=('金额', 'mean'),
    交易客户数=('客户ID', 'nunique')
)
# 4. 排序与输出
result = result.sort_values(['地区', '月份']).reset_index(drop=True)

输出示例:

地区 月份 总销售额 平均订单金额 交易客户数
华东 1 58900 8 230
华东 2 62150 3 245
华北 1 42100 5 198

关键技巧nunique()统计唯一客户数,避免重复计数同一客户的多笔订单。


实战案例二:用户行为按付费等级分组分析

场景:

用户表user_behavior包含:用户ID, 付费等级(免费/月卡/年卡), 登录次数, 累计消费, 活跃天数,运营需要对比不同等级的用户行为差异。

分组聚合+多重统计:

# 按等级分组,计算多个指标的均值和中位数
result = df.groupby('付费等级').agg(
    平均登录次数=('登录次数', 'mean'),
    登录次数中位数=('登录次数', 'median'),
    平均累计消费=('累计消费', 'mean'),
    人均活跃天数=('活跃天数', 'mean'),
    总人数=('用户ID', 'count')
).round(2)  # 保留两位小数

输出:

付费等级 平均登录次数 登录次数中位数 平均累计消费 人均活跃天数 总人数
免费 3 0 0 2 1200
月卡 7 0 5 9 450
年卡 2 0 3 1 120

业务洞察:年卡用户月均消费是月卡的7倍,但人数仅为1/4,说明高价值用户值得投入更多资源维护。


分组后的聚合运算进阶

agg():一次调用多个聚合函数

df.groupby('地区')['金额'].agg(['sum', 'mean', 'std', 'max', 'min'])

transform():保持原行结构的分组运算

场景:给每行增加一列“该客户所在地区的平均消费额”

df['地区平均消费'] = df.groupby('地区')['金额'].transform('mean')

注意:transform返回与原DataFrame相同长度的Series,非常适合做特征工程。

filter():按分组条件筛选数据

需求:只保留“总销售额 > 5万”的地区数据

filtered = df.groupby('地区').filter(lambda x: x['金额'].sum() > 50000)

常见错误与性能优化

❌ 错误1:忽略数据类型导致内存爆增

# 错误示范:分组列含高基数字符串导致分组非常慢
df.groupby('用户ID').agg(...)  # 如果用户ID是object类型,且百万级,慎用
# 正确做法:转化为category类型
df['用户ID'] = df['用户ID'].astype('category')

❌ 错误2:多键分组时误用索引

# 如果只写df.groupby(['A','B']).sum(),结果会以A,B作为MultiIndex
# 若要保留为普通列,加 as_index=False

🚀 性能优化建议:

  • 对数值列先转化为float32而非float64,可降低一半内存;
  • 使用nunique(dropna=False)时,明确是否包含空值;
  • 大数据集下,优先用groupby().agg(numpy_func)避免Python层循环;
  • 考虑dask.dataframe并行化(数据超千万行时)。

Q&A问答集锦

Q1: groupby之后怎么访问某个组的原始数据? A: 用get_group()方法,例如grouped = df.groupby('地区'),然后grouped.get_group('华东')返回仅华东的DataFrame。

Q2: 分组后如何保留所有原始列,只对部分列聚合? A: 使用agg()配合字典。df.groupby('地区').agg({'金额':'sum','客户ID':'nunique','日期':'first'}),未被聚合的列会被丢弃,若想保留可以加上'日期':'first'或'last'

Q3: 数据有缺失值,分组时被忽略怎么办? A: 默认groupby(dropna=True)会忽略分组列中的NaN行,如需保留NaN作为一组,设置dropna=False

Q4: 分组统计后的结果如何排序?比如按总销售额降序。 A: result = df.groupby('地区')['金额'].sum().sort_values(ascending=False),若用as_index=False分组,则用sort_values(by='总销售额')

Q5: 能否按自定义规则分组?比如按金额范围0-100,100-500,500+? A: 可以,先创建分组列:df['金额区间'] = pd.cut(df['金额'], bins=[0,100,500,99999], labels=['低','中','高']),再按此列分组。

Q6: 分组后不同列应用不同聚合函数,怎么写更简洁? A: 使用named aggregation(Python 3.6+):

df.groupby('地区').agg(
    avg_amount=('金额', 'mean'),
    total_amount=('金额', 'sum'),
    unique_customers=('客户ID', 'nunique')
)

Q7: 数据量350万行,单次分组聚合耗时30秒,能否优化? A: 检查是否因object类型导致慢——建议转为category;尝试用engine='numba'加速(需安装numba);若分组的列超大尺寸,考虑groupby().apply()是否可替换为groupby().transform()以降低中间结果体积。


数据分组是Pandas中最核心的“切-聚-展”操作,从单键简单统计到多键分层聚合,再到复杂业务下的条件筛选与性能调优,掌握groupby()的灵活运用,足以应对日常90%以上的数据加工需求,建议读者在自己的真实数据集上,尝试本文所有案例,并逐步引入大数据场景下的优化技巧。

抱歉,评论功能暂时关闭!