Python案例如何用Pandas做数据分组统计

wen python案例 1

Python案例实战:如何用Pandas做数据分组统计(从入门到高阶)

目录导读

  1. 数据分组统计的核心价值
  2. 环境准备与基础数据构建
  3. 分组统计的四种核心模式(含代码解析)
  4. 常见业务场景实战案例
  5. 分组统计的常见坑与避坑指南
  6. 问答环节:解决你的高频疑惑

数据分组统计的核心价值

在日常数据分析和业务运营中,我们经常需要回答这样的问题:

Python案例如何用Pandas做数据分组统计

  • 每个月的销售额是多少?
  • 不同城市用户的平均消费金额如何?
  • 按产品类别统计订单总数和总金额?

这些问题的核心都指向同一个操作:对数据按某个维度分组,然后对各组进行聚合统计,Pandas作为Python最强大的数据处理库,其groupby机制正是解决这类问题的利器。

根据Stack Overflow的统计,groupby在Pandas相关提问中占比超过15%,可以说它是数据分析师必须掌握的核心技能,接下来我们将通过实际案例,手把手教你如何用Pandas完成各类分组统计任务。


环境准备与基础数据构建

首先确保你已安装Pandas库:

pip install pandas

我们将创建一份模拟的电商订单数据来演示所有案例:

import pandas as pd
import numpy as np
# 生成示例数据
np.random.seed(42)
data = {
    'order_id': range(1, 101),
    'city': np.random.choice(['北京', '上海', '广州', '深圳', '杭州'], 100),
    'category': np.random.choice(['电子产品', '服装', '食品', '家居用品'], 100),
    'amount': np.random.uniform(50, 500, 100).round(2),
    'quantity': np.random.randint(1, 5, 100),
    'date': pd.date_range('2024-01-01', periods=100, freq='D')
}
df = pd.DataFrame(data)
print(df.head())

输出示例:

   order_id city category  amount  quantity       date
0         1  北京     电子产品 123.45         3 2024-01-01
1         2  上海       服装 278.90         2 2024-01-02
2         3  广州     家居用品 345.12         4 2024-01-03
...

分组统计的四种核心模式(含代码解析)

1 基础分组:单列分组 + 单指标聚合

需求:计算每个城市的平均订单金额。

# 方式1:直接使用groupby后接聚合函数
result = df.groupby('city')['amount'].mean()
print(result)

输出

city
上海    286.74
北京    272.19
广州    291.64
深圳    268.67
杭州    278.53
Name: amount, dtype: float64

代码解读

  • df.groupby('city'):按'city'列分组
  • ['amount']:从分组中选择要计算的列
  • .mean():计算平均值
  • 返回Series对象,索引为分组键

2 多列分组 + 多指标聚合

需求:统计每个城市、每个产品类别的总订单金额和订单数量。

# 方式2:使用agg函数指定多个聚合方法
result = df.groupby(['city', 'category']).agg(
    total_amount=('amount', 'sum'),
    order_count=('order_id', 'count'),
    avg_quantity=('quantity', 'mean')
).reset_index()
print(result.head())

输出

   city category  total_amount  order_count  avg_quantity
0  上海     家居用品        1523.86            5          2.8
1  上海     电子产品        1245.67            4          2.5
2  上海       服装         2678.90            9          3.1
...

代码解读

  • groupby(['city', 'category']):按多列分组
  • agg():接受一个字典,key为新列名,value为(原列名, 聚合函数)的元组
  • reset_index():将分组键转为普通列,便于后续处理

3 分组后应用自定义函数

需求:计算每个城市的销售额中位数和离散系数(标准差/均值)。

def cv(x):
    """计算离散系数"""
    return x.std() / x.mean() if x.mean() != 0 else 0
result = df.groupby('city')['amount'].agg(
    median_amount='median',
    coefficient_var=cv
).reset_index()
print(result)

输出

   city  median_amount  coefficient_var
0  上海         290.25          0.3589
1  北京         270.50          0.3812
...

4 分组后转换与过滤

transform:保持原数据行数,添加分组统计值

需求:给每行数据添加该城市订单金额的平均值。

df['city_avg_amount'] = df.groupby('city')['amount'].transform('mean')
print(df[['city', 'amount', 'city_avg_amount']].head())

输出

   city  amount  city_avg_amount
0  北京  123.45           272.19
1  上海  278.90           286.74
2  广州  345.12           291.64
...
filter:按分组条件筛选数据

需求:保留平均订单金额高于280的城市的所有订单。

filtered_df = df.groupby('city').filter(lambda x: x['amount'].mean() > 280)
print(filtered_df['city'].value_counts())

输出

上海    20
广州    20
杭州    20
Name: city, dtype: int64

常见业务场景实战案例

案例1:时间序列分组统计(按月聚合)

需求:统计2024年每月的销售额和订单量。

# 添加月份列
df['month'] = df['date'].dt.month
monthly_stats = df.groupby('month').agg(
    total_sales=('amount', 'sum'),
    order_count=('order_id', 'count')
).reset_index()
print(monthly_stats)

输出

   month  total_sales  order_count
0      1      12567.8           45
1      2      13456.2           48
2      3      11234.5           40

案例2:分层统计(嵌套分组后计算占比)

需求:计算每个城市各品类的销售占比。

# 先计算每个城市的总销售额
city_total = df.groupby('city')['amount'].sum().rename('city_total')
# 计算每个城市各品类销售额
city_cat = df.groupby(['city', 'category'])['amount'].sum().reset_index()
# 合并并计算占比
city_cat = city_cat.merge(city_total, on='city')
city_cat['sales_pct'] = (city_cat['amount'] / city_cat['city_total'] * 100).round(2)
print(city_cat.head())

案例3:分组后排序取Top N

需求:找出每个城市金额最高的前3笔订单。

top3_per_city = df.groupby('city').apply(
    lambda x: x.nlargest(3, 'amount')
).reset_index(drop=True)
print(top3_per_city[['city', 'amount', 'date']])

输出

   city  amount       date
0  上海  498.32 2024-03-15
1  上海  487.21 2024-02-28
2  上海  476.89 2024-01-19
...

分组统计的常见坑与避坑指南

坑1:忘记reset_index导致索引混乱

错误示例

result = df.groupby('city')['amount'].mean()
# 此时result为Series,索引是city
# 直接与DataFrame合并可能出错

正确做法

result = df.groupby('city')['amount'].mean().reset_index()
# 或者使用as_index=False
result = df.groupby('city', as_index=False)['amount'].mean()

坑2:groupby后列选择顺序错误

错误示例

# 想选amount和quantity,但写反了
result = df.groupby('city')[['quantity', 'amount']].mean()

注意groupby后直接.mean()会计算所有数值列,如果只想计算指定列,一定要用双括号明确选择。

坑3:聚合函数命名冲突

当使用agg时,如果聚合函数名称与列名重复,可能引发意外结果,建议使用新列名明确指定。

坑4:时间分组时未处理时区或日期格式

最佳实践:始终确保日期列是datetime类型,使用pd.to_datetime()进行转换。


问答环节:解决你的高频疑惑

Q1:groupby后为什么返回Series而不是DataFrame?

A:当只选择单列时,Pandas默认返回Series,如果你需要DataFrame格式,可以使用reset_index()as_index=False参数,或者选择多列(用双括号)。

Q2:如何同时计算多个聚合函数并保持列名清晰?

A:使用agg函数配合元组列表,可以自定义输出列名。

df.groupby('city').agg(
    avg_amount=('amount', 'mean'),
    max_amount=('amount', 'max'),
    total_quantity=('quantity', 'sum')
)

Q3:多个分组键时如何控制排序?

A:默认情况下,groupby会按分组键排序,如果希望保持原始出现顺序,可以设置sort=False

df.groupby('city', sort=False).mean()

Q4:可以分组后对不同列应用不同聚合函数吗?

A:当然可以,这正是agg最强大的功能,给不同列分配不同聚合函数:

df.groupby('city').agg(
    avg_amount=('amount', 'mean'),
    total_qty=('quantity', 'sum'),
    distinct_orders=('order_id', 'nunique')
)

Q5:处理大型数据集时groupby性能如何优化?

A:建议:

  • 尽量使用内置聚合函数而非自定义函数
  • 对分组列使用分类数据类型(CategoricalDtype)
  • 先过滤无关数据,再进行分组
  • 考虑使用numpy向量化操作替代部分分组统计

通过本文的案例,你应该已经掌握了Pandas分组统计的完整操作流程:从最基础的groupby+聚合函数,到多分组键的复杂统计,再到实际业务场景中的应用,分组统计的核心在于明确分组键、选择聚合列、确定聚合函数这三步。

建议你将本文的代码复制到自己的Python环境中运行一遍,并尝试修改分组键或聚合函数,观察结果的变化,只有动手实践,才能真正掌握这项数据分析的核心技能。

如果你在实际工作中遇到特殊的分组统计需求,欢迎在评论区留言讨论。

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