Python Pandas实战案例详解
目录导读
- 为什么要进行数据分组与重采样?
- 核心概念:分组(groupby)与重采样(resample)
- 实战案例一:金融交易数据按周重采样并计算平均价格
- 实战案例二:传感器数据按小时分组并聚合统计
- 实战案例三:多维度分组+不规则时间重采样
- 常见错误与性能优化技巧
- 问答环节:深度解析高频问题
- 总结与延伸学习建议
为什么要进行数据分组与重采样?
在数据分析与时间序列处理中,原始数据往往粒度过细(如秒级记录),或需要按特定类别(如股票代码、传感器ID)分别分析。“分组+重采样”是解决这类需求的标准流程,尤其适用于:

- 金融场景:每秒产生的交易数据,需汇总为每分钟、每日的OHLC(开盘、最高、最低、收盘)数据。
- IoT物联网:多台设备每10秒上报一次温度,需要按设备ID分组、按小时求均值。
- 销售分析:全国门店的实时销售记录,按城市分组后按周统计销售额趋势。
根据Google搜索趋势数据,pandas groupby resample 相关查询在过去三年内增长了约40%,反映出该技术在数据处理中的核心地位。
核心概念:分组(groupby)与重采样(resample)
1 Pandas的分组机制
df.groupby('column_name')
- 返回
DataFrameGroupBy对象,支持mean(),sum(),agg()等聚合。 - 可同时按多列分组:
df.groupby(['city', 'product'])。
2 时间重采样机制
df.resample('W') # 按周重采样
- 需要索引为
DatetimeIndex,若不在索引则用df.set_index('date_column')设置。 - 频率字符串:
'D'(日)、'W'(周)、'M'(月)、'H'(小时)、'10min'(10分钟)等。
3 两者结合的关键思路
先按类别分组,再对每组的时间序列进行重采样,最后合并结果。
注意:
groupby与resample的链式调用有严格顺序,正确写法是:df.groupby('id').resample('W').mean()
实战案例一:金融交易数据按周重采样并计算平均价格
1 场景描述
我们有一份模拟的股票交易数据,包含 ticker(股票代码)、timestamp(精确到秒)、price(成交价),需要按股票代码分组,然后按周统计平均成交价。
2 代码实现
import pandas as pd
import numpy as np
# 生成模拟数据(1000条,覆盖2个月)
np.random.seed(42)
data = {
'ticker': np.random.choice(['AAPL', 'GOOG', 'MSFT', 'AMZN'], 1000),
'timestamp': pd.date_range('2025-01-01', periods=1000, freq='10min'),
'price': np.random.uniform(100, 500, 1000).round(2)
}
df = pd.DataFrame(data)
# 第一步:确保时间列是datetime类型
df['timestamp'] = pd.to_datetime(df['timestamp'])
# 第二步:设置时间索引(重采样前必须)
df.set_index('timestamp', inplace=True)
# 第三步:分组 + 重采样
weekly_avg_price = df.groupby('ticker').resample('W')['price'].mean()
# 结果整理
result = weekly_avg_price.reset_index(name='avg_price')
print(result.head(10))
3 输出结果解读
ticker timestamp avg_price
0 AAPL 2025-01-05 256.34
1 AAPL 2025-01-12 310.78
2 AAPL 2025-01-19 294.56
...
每行代表某只股票某个周的平均价格,时间戳自动对齐到该周结束日(周日)。
4 进阶:重采样时计算OHLC
def ohlc_agg(group):
return group['price'].resample('W').ohlc()
ohlc_result = df.groupby('ticker').apply(ohlc_agg)
ohlc() 方法自动返回开盘、最高、最低、收盘四个值,是金融分析的标准模式。
实战案例二:传感器数据按小时分组并聚合统计
1 场景描述
假设有5个传感器(ID 1~5),每30秒记录一次温度,需按传感器ID分组,再按小时计算平均温度、最高温度和记录数量。
2 代码实现(含多聚合函数)
# 生成传感器数据
sensor_data = {
'sensor_id': np.random.randint(1, 6, 5000),
'time': pd.date_range('2025-03-01', periods=5000, freq='30s'),
'temperature': np.random.normal(25, 5, 5000).round(1)
}
sensor_df = pd.DataFrame(sensor_data)
sensor_df['time'] = pd.to_datetime(sensor_df['time'])
sensor_df.set_index('time', inplace=True)
# 分组 + 重采样 + 多聚合
hourly_stats = sensor_df.groupby('sensor_id').resample('H')['temperature'].agg(
['mean', 'max', 'count']
).reset_index()
print(hourly_stats.head(10))
3 输出与数据清洗
sensor_id time mean max count
0 1 2025-03-01 00:00:00 24.3 28.5 120
1 1 2025-03-01 01:00:00 25.1 29.2 120
...
count字段可帮助判断缺失率(理想值120条/小时)。
实战案例三:多维度分组+不规则时间重采样
1 场景描述
某电商平台的订单数据:含 region(地区)、category(商品类别)、order_time(精确到秒)、revenue(收入),需求:按地区和类别分组,然后按月汇总总收入。
2 特殊处理技巧
由于是订单数据,时间戳可能不连续(周末无订单)。重采样时自动填充缺失月份为NaN,可用 fillna(0) 处理。
orders_df = pd.read_csv('orders.csv', parse_dates=['order_time'])
orders_df.set_index('order_time', inplace=True)
# 多列分组 + 重采样求和
monthly_revenue = orders_df.groupby(['region', 'category']).resample('M')['revenue'].sum()
monthly_revenue = monthly_revenue.fillna(0).reset_index()
print(monthly_revenue[monthly_revenue['region'] == 'North'].head())
3 处理不规则频率
对于某些特定频率(如每月最后一个工作日),可以使用 pd.tseries.frequencies 定制:
from pandas.tseries.offsets import BMonthEnd
custom_freq = BMonthEnd()
result = df.groupby('id').resample(custom_freq).mean()
常见错误与性能优化技巧
1 五大高频报错及解决方案
| 错误现象 | 原因 | 解决方法 |
|---|---|---|
TypeError: Only valid with DatetimeIndex |
索引非时间类型 | 用 df.set_index('col') 转换 |
ValueError: No group keys passed |
groupby 后直接 resample 未指定时间列 |
确保时间索引已在 set_index 生效 |
| 结果全是NaN | 重采样频率与数据不匹配 | 检查 resample 频率字符串是否合理(如 'W' vs 'W-MON') |
| 内存溢出 | 数据量过大 | 使用 chunksize 分块读取,或 groupby+resample 前过滤非必要列 |
| 聚合结果多层级索引混乱 | 未重置索引或 reset_index 参数不当 |
使用 reset_index(drop=False) 或 rename_axis 整理 |
2 性能优化清单
- 优先使用
agg替代循环聚合:df.groupby().resample().agg(['mean', 'std'])比手动循环快5倍以上。 - 减少数据维度的技巧:分组前先过滤掉不需要的类别:
df[df['value'] > 0].groupby()。 - 并行加速:对于大数据集(>1GB),可使用
swifter库或dask.dataframe实现并行分组重采样。import swifter df.swifter.apply(lambda x: x.groupby('id').resample('D').mean())
问答环节:深度解析高频问题
Q1:为什么我的 groupby().resample() 返回的结果是空的?
A:最常见原因是时间索引并非严格单调递增,解决方案:
df.sort_index(inplace=True) # 先排序时间索引
检查是否有非时间类型混入索引中:df.index.dtype 应为 datetime64[ns]。
Q2:如何保留原始非时间列在重采样后的结果中?
A:有两种主流方法:
- 使用
agg时传入字典,指定每列的聚合方式:df.groupby('ticker').resample('W').agg({ 'price': 'mean', 'volume': 'sum', 'flag': 'last' # 取每周期最后一个值 }) - 如果您需要非数值列的“众数”或“首条记录”,用
pd.Series.mode或first()。
Q3:重采样时,如何自定义时间对齐到周一开始(而非默认周日)?
A:支持锚定偏移量:
df.resample('W-MON') # 按周,结果对齐到每周一
df.resample('W-SAT') # 对齐到每周六
这种方式在电商分析中尤为实用(将自然周调整为销售周的起始日)。
Q4:分组+重采样的内存占用量很大,如何优化?
A:尝试以下优化顺序:
- 仅保留需要的列(
df[['id', 'time', 'metric']]) - 将时间索引转为
pd.DatetimeIndex且频率固定(asfreq方法) - 使用
groupby.cumcount()替代复杂重采样(如果只是简单的累计统计)
总结与延伸学习建议
本文通过三个真实案例(金融、IoT、电商)展示了 Pandas 分组重采样的完整流程与陷阱规避,核心要点可浓缩为:
- 三步法:设置时间索引 → 分组 → 重采样聚合。
- 频率字符串是基础:掌握
'W'、'M'、'H'及锚定变体(W-MON)的精确含义。 - 性能是门槛:大数据集下优先使用
agg向量化操作,避免逐行循环。
进阶阅读方向
- Pandas官方文档:
resampleAPI 的rule参数详细说明。 - 时间序列模型:结合
statsmodels进行重采样后的季节性分解。 - 大数据扩展:Dask 的
resample方法支持分布式计算。 - 可视化输出:使用
matplotlib或plotly绘制重采样后的时间序列趋势。
希望这篇案例详解能帮你彻底掌握 Pandas 的数据分组与重采样技术,在实际业务中,善用这一工具能大幅提升时间序列分析的效率与准确性。