Python案例详解Pandas数据分组重采样方法(附完整代码)
目录导读
- 什么是Pandas数据分组重采样?
- 为什么需要分组重采样?——真实业务场景
- 核心函数:
groupby()+resample()的黄金组合 - 案例实战:股票日行情转周K线、销售数据月度聚合
- 常见错误与避坑指南
- 性能优化技巧(大数据量场景)
- 问答专区:你关心的5个高频问题
什么是Pandas数据分组重采样?
分组重采样是指先按照某个类别(如股票代码、门店ID)对数据进行分组,然后在每个分组内部按时间维度进行频率转换(将分钟数据汇总为小时数据,或日数据转为周数据)。

简单说就是:先分组,再重采样,在Pandas中,我们通过 groupby() 与 resample() 的链式调用实现。
为什么需要分组重采样?——真实业务场景
假设你是一家电商平台的数据分析师,每天需要处理以下任务:
- 场景A:全国100家门店每小时的销售记录,要输出每个门店的日销售额。
- 场景B:沪深两市4000只股票每分钟的行情数据,需要生成每只股票的周K线。
- 场景C:物联网传感器每隔10秒上报的温湿度数据,需要按小时统计每个传感器平均温湿度。
如果不分组直接重采样,你会把不同门店、不同股票的数值混在一起,结果毫无意义。分组重采样正是解决这类“多实体+时间序列”问题的标准方法。
核心函数:groupby() + resample() 的黄金组合
Pandas实现分组重采样的标准语法为:
df.groupby('分组字段').resample('时间频率').聚合函数()
关键点:
- 分组字段:通常是类别变量(如
stock_code、store_id) - 时间频率:
'D'(日)、'W'(周)、'M'(月)、'H'(小时)、'T'(分钟)等 - 聚合函数:
mean()、sum()、ohlc()(金融专用)、自定义函数
注意:resample() 要求时间列必须是 DatetimeIndex 或 pd.to_datetime() 转换后的列,如果时间列不是索引,需指定 on 参数。
案例实战:完整Python代码演示
案例1:金融股票数据——日行情转周K线
数据模拟(实际可从雅虎财经等API获取)
import pandas as pd
import numpy as np
# 生成模拟数据:两只股票,5分钟频次,30天
np.random.seed(42)
dates = pd.date_range('2024-01-01', '2024-01-30', freq='5T')
stocks = ['AAPL', 'GOOGL']
data = []
for stock in stocks:
price = np.random.uniform(100, 200, len(dates))
data.extend([[stock, d, p] for d, p in zip(dates, price)])
df = pd.DataFrame(data, columns=['stock', 'time', 'close'])
print("原始数据形状:", df.shape)
执行分组重采样(转换为周OHLC格式)
# 关键步骤:先按股票分组,再按周重采样,输出开盘、最高、最低、收盘
weekly_ohlc = df.groupby('stock').resample('W', on='time')['close'].ohlc().reset_index()
print(weekly_ohlc.head(10))
输出解析:你会看到每个股票每周一条记录,包含Open、High、Low、Close四列,这正是金融领域标准的周K线数据结构。
案例2:零售销售数据——按门店+月汇总
# 模拟零售数据:3家门店,每天销售额
sales_data = {
'store': ['A', 'B', 'C'] * 100,
'date': pd.date_range('2024-01-01', periods=300, freq='D'),
'revenue': np.random.randint(1000, 5000, 300)
}
df_sales = pd.DataFrame(sales_data)
# 按门店分组,按月汇总销售额
monthly_sales = df_sales.groupby('store').resample('M', on='date')['revenue'].sum()
print(monthly_sales)
常见错误与避坑指南
| 错误类型 | 典型代码 | 错误原因 | 正确做法 |
|---|---|---|---|
| 索引错误 | df.resample('D').mean() |
时间列不是索引 | 加on参数或先set_index() |
| 分组后索引混乱 | groupby().resample()后直接plot |
结果有多层索引 | 用reset_index()平整化 |
| 缺失时间异常 | 数据日期不连续 | 重采样后出现NaN | 用.ffill()或.fillna(0) |
| 性能问题 | 逐行循环分组 | 大数据量时极慢 | 用groupby().resample()向量化 |
最佳实践建议:先确保时间列为 datetime 类型,且数据按时间排序,可大幅提升效率。
性能优化技巧(大数据量场景)
当数据量超过100万行时,以下技巧能显著提升速度:
- 使用
resample()的on参数:避免多次set_index()导致内存拷贝 - 减少分组数量:如果分组字段有100万个唯一值,考虑先按天存分区文件
- 聚合函数选择:
sum()/mean()比自定义lambda快3-5倍 - 关闭排序:
groupby(sort=False)避免额外排序开销
问答专区:你关心的5个高频问题
Q1:分组重采样和普通重采样有什么区别?
A:普通重采样针对单条时间序列(如一只股票),分组重采样针对多实体(如100只股票)分别做时间转换,两者语法差异在于是否先调用 groupby()。
Q2:时间列不是索引时如何处理?
A:使用 on 参数指定时间列:
df.groupby('stock').resample('W', on='trade_date').mean()
Q3:重采样后数据量变少,是否丢失信息?
A:不是丢失,是聚合——例如从分钟变为小时,一定会用均值或总和代表该时间段,这是合理的数据降维。
Q4:能否对重采样后的数据做窗口计算(如滚动均值)?
A:可以,在重采样结果基础上再次使用 .rolling(window=3).mean(),先聚合再平滑。
Q5:代码运行速度很慢,有什么建议?
A:优先检查数据量是否过大,尝试先用小数据测试逻辑;若需频繁执行,考虑将分组重采样后的结果存入数据库或分区Parquet文件。
延伸推荐:如果你想进一步学习,可以搜索“Pandas groupby resample multiple aggregations” 查看如何使用
agg()同时计算均值、中位数、标准差等多种统计量。
本文示例代码均基于Python 3.10及Pandas 2.0+测试通过,建议使用Jupyter Notebook交互式运行以观察每一步输出。