Python案例详解如何用Pandas做数据分组重采样(附实战代码)
目录导读
- 什么是数据分组重采样?为什么它如此重要?
- Pandas重采样基础:resample() 与 groupby() 的区别
- 高频实战案例:股票交易数据按周重采样
- 按类别分组后重采样:零售销售数据月汇总
- 时间序列 + 多列聚合:同时计算均值、总和与最大值
- 常见错误与调优技巧
- 问答环节:你可能会遇到的5个关键问题
什么是数据分组重采样?为什么它如此重要?
在数据分析中,原始数据往往以“秒级”或“日级”频率记录,但业务决策通常需要“周级”或“月级”的汇总视图。数据分组重采样,即先按某个分类字段(如城市、产品ID)分组,再对每个组内的时间序列数据进行频率转换(如从每日转为每周)。

为什么重要?
- 减少数据量,提升后续模型训练速度
- 匹配业务汇报周期(如周报、月报)
- 消除高频噪声,暴露长期趋势
案例场景:某电商平台需要按“商品类别”统计“每周平均销量”,原始数据是每分钟的订单记录,直接按周平均会掩盖类别差异,必须先分组后重采样。
Pandas重采样基础:resample() 与 groupby() 的区别
核心API对比
| 操作 | 适用场景 | 关键参数 |
|---|---|---|
df.resample('W').mean() |
单时间序列 | 频率字符串('W','M','Q') |
df.groupby('category').resample('W').mean() |
多分类+时间序列 | 先分组,再重采样 |
实现逻辑模型
原始数据 → 按category分组 → 每组形成一个子DataFrame → 每组调用resample() → 合并结果
代码示例(模拟数据)
import pandas as pd
import numpy as np
# 生成模拟数据:2种商品,2023年每日数据
dates = pd.date_range('2023-01-01', '2023-12-31', freq='D')
df = pd.DataFrame({
'date': np.tile(dates, 2),
'product': ['A']*len(dates) + ['B']*len(dates),
'sales': np.random.randint(100, 500, len(dates)*2)
})
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
# 关键操作:分组 + 重采样
grouped_resampled = df.groupby('product').resample('W').sum()
print(grouped_resampled.head())
输出解释:每一行代表某商品在某周的总销售额,索引为 (product, date) 多级索引。
高频实战案例:股票交易数据按周重采样
业务需求
给定股票代码、日期、收盘价、交易量,要求计算每只股票 每周最高价、最低价、平均价和总交易量。
完整代码
import yfinance as yf # 真实数据源,若无法联网可用本地csv替代
# 下载股票数据(示例:AAPL与GOOG)
tickers = ['AAPL', 'GOOG']
data = yf.download(tickers, start='2023-01-01', end='2023-12-31', group_by='ticker')
# 准备多级索引
df_list = []
for ticker in tickers:
temp = data[ticker].copy()
temp['ticker'] = ticker
df_list.append(temp)
df = pd.concat(df_list)
df.reset_index(inplace=True)
df.set_index(['ticker', 'Date'], inplace=True)
# 分组重采样(关键步骤)
weekly = df.groupby(level='ticker').resample('W').agg({
'Close': ['max', 'min', 'mean'],
'Volume': 'sum'
})
print(weekly.head(10))
输出结果样式
Close Volume
max min mean sum
ticker Date
AAPL 2023-01-08 133.34 126.36 129.85 62050000
2023-01-15 135.45 131.26 133.12 58420000
GOOG 2023-01-08 89.12 85.30 87.45 43010000
关键点:groupby(level='ticker') 用于处理多级索引的第一层分组。
按类别分组后重采样:零售销售数据月汇总
数据特点
每行包含:store_id, date, department, sales_amount
优化写法(避免多级索引混乱)
# 读取零售数据(假设已导入)
df = pd.read_csv('retail_sales.csv', parse_dates=['date'])
# 方法1:先set_index再groupby
df.set_index('date', inplace=True)
monthly = df.groupby('department').resample('M')['sales_amount'].sum().reset_index()
print(monthly.head())
# 方法2:使用groupby + apply(适合更复杂逻辑)
def monthly_sum(group):
return group.resample('M')['sales_amount'].sum()
result = df.groupby('department').apply(monthly_sum)
注意事项
- 如果数据量大,
reset_index()可以避免多级索引的调用代价 - 对于缺失月份,可使用
.asfreq()补全为空值
时间序列 + 多列聚合:同时计算均值、总和与最大值
高级聚合技巧
# 假设有4列:temperature, humidity, wind_speed, pressure
df = pd.read_csv('weather_daily.csv', parse_dates=['date'])
df.set_index('date', inplace=True)
# 按城市分组,按月重采样,并指定每列的聚合方式
monthly_weather = df.groupby('city').resample('M').agg({
'temperature': 'mean',
'humidity': 'mean',
'wind_speed': 'max',
'pressure': ['min', 'max']
})
print(monthly_weather.head())
输出截图说明
- 列名变为多级:
temperature列变('temperature', 'mean') - 可通过
monthly_weather.columns = ['_'.join(col).strip() for col in monthly_weather.columns]简化
常见错误与调优技巧
错误1:忘记将时间列设为索引
- 后果:
resample()报错AttributeError: 'Index' object has no attribute 'freq' - 解决:
df.set_index('date', inplace=True)
错误2:分组后索引层级混乱
- 现象:
groupby('A').resample('M')返回三层索引 - 解决:清预期层级,使用
.reset_index(level=1, drop=True)或直接reset_index()
调优技巧
- 使用
sort=False:若原始数据已排序,可提速 - 使用
apply替代循环:永远不要写for group in df.groupby('A') - 数据量超1亿行:考虑
Dask或modin扩展库
问答环节:你可能会遇到的5个关键问题
Q1:重采样后数据变少了,是不是丢失了信息?
A:不是丢失,而是聚合,每日数据 -> 每周平均”,压缩了粒度但保留了趋势,若需保留极端值,可用 max/min 聚合。
Q2:如何从周数据再重采样为月数据?
A:直接 resample('M') 即可,Pandas会自动识别基于周索引的周期端点。
Q3:分组+重采样后如何还原为扁平DataFrame?
A:使用 reset_index() 并重命名列,
monthly.reset_index(inplace=True)
monthly['date'] = monthly['date'].dt.to_period('M')
Q4:有些组在特定时间段没有数据,如何补全?
A:使用 .asfreq('W', fill_value=0) 在重采样后填充缺失的时间点。
Q5:groupby().resample() 和 resample().groupby() 有区别吗?
A:前者是先分组再对每组分别重采样(常见需求),后者会先对整体时间序列重采样再分组,逻辑相反,通常不推荐。
Pandas的分组重采样功能是时间序列分析的“杀手锏”,通过本文的案例,你已掌握以下核心技能:
- 区分
resample()与groupby().resample() - 处理多级索引带来的复杂性
- 针对不同业务场景选择合适的聚合函数
你可以打开你的数据集,尝试按“地区-产品-月份”做一次重采样分析,你会发现隐藏在高频数据下的业务规律。