我来通过一个实际案例演示如何使用Pandas进行数据分组重采样(GroupBy + Resample)。

案例:股票交易数据分析
假设我们有多只股票的分钟级交易数据,需要按天汇总每只股票的统计指标。
创建示例数据
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# 创建示例数据
np.random.seed(42)
# 生成日期范围
date_range = pd.date_range('2024-01-01', '2024-01-07', freq='5min')
# 创建多只股票的数据
stocks = ['AAPL', 'GOOGL', 'MSFT']
data_list = []
for stock in stocks:
n = len(date_range)
stock_data = pd.DataFrame({
'stock': stock,
'timestamp': date_range,
'price': 100 + np.random.randn(n).cumsum() * 0.5,
'volume': np.random.randint(1000, 10000, n)
})
data_list.append(stock_data)
# 合并所有数据
df = pd.concat(data_list, ignore_index=True)
print("原始数据预览:")
print(df.head(10))
print(f"\n数据形状: {df.shape}")
设置时间索引并分组重采样
# 设置时间索引
df.set_index('timestamp', inplace=True)
# 按股票分组,并按天重采样
daily_stats = df.groupby('stock').resample('1D').agg({
'price': ['first', 'last', 'max', 'min', 'mean', 'std'],
'volume': ['sum', 'mean', 'max']
})
print("每日股票统计:")
print(daily_stats.head(20))
重命名列名
# 重命名多级列名
daily_stats.columns = ['_'.join(col).strip() for col in daily_stats.columns.values]
daily_stats = daily_stats.reset_index()
print("重命名后的数据:")
print(daily_stats.head(10))
高级重采样操作
# 计算每只股票的日收益率
price_daily = df.groupby('stock')['price'].resample('1D').last()
returns = price_daily.groupby('stock').pct_change() * 100
print("每日收益率 (%):")
print(returns)
# 计算滚动统计量
rolling_stats = df.groupby('stock').rolling(window='2D').agg({
'price': ['mean', 'std'],
'volume': ['sum']
})
print("\n滚动统计(2天窗口):")
print(rolling_stats.head(20))
复杂数据处理案例
# 计算每周开盘价、最高价、最低价、收盘价和成交量总和
weekly_data = df.groupby('stock').resample('1W').agg({
'price': ['first', 'max', 'min', 'last'],
'volume': 'sum'
})
weekly_data.columns = ['open', 'high', 'low', 'close', 'volume']
weekly_data = weekly_data.reset_index()
print("周度数据(OHLC格式):")
print(weekly_data)
# 计算每只股票午前和午后的平均成交量
def time_of_day(hour):
if hour < 12:
return 'morning'
else:
return 'afternoon'
df['time_period'] = df.index.hour.map(time_of_day)
period_volume = df.groupby(['stock', 'time_period'])['volume'].mean()
print("\n午前午后平均成交量:")
print(period_volume)
实际应用:异常检测
# 检测价格异常波动
def detect_outliers(group):
mean = group['price'].mean()
std = group['price'].std()
return (group['price'] - mean).abs() > 2 * std
outliers = df.groupby('stock').apply(detect_outliers)
outlier_points = df[outliers]
print(f"发现异常点数量: {len(outlier_points)}")
if len(outlier_points) > 0:
print("\n异常点示例:")
print(outlier_points.head())
常见重采样频率
# 不同时间频率
freqs = {
'B': '工作日',
'W': '周',
'M': '月',
'Q': '季度',
'Y': '年',
'H': '小时',
'T': '分钟',
'S': '秒'
}
处理缺失数据
# 重采样后填充缺失值
daily_data = df.groupby('stock').resample('1D').agg({
'price': 'mean'
})
# 前向填充
daily_data_filled = daily_data.fillna(method='ffill')
# 线性插值
daily_data_interpolated = daily_data.interpolate()
自定义聚合函数
# 自定义聚合函数
def price_range(prices):
return prices.max() - prices.min()
custom_agg = df.groupby('stock').resample('1D').agg({
'price': ['mean', price_range],
'volume': 'sum'
})
这个案例展示了Pandas数据分组重采样的核心用法,包括:
- 基本分组重采样
- 多级列名处理
- 滚动窗口计算
- 时间周期聚合
- 自定义函数应用
你可以根据实际业务需求调整重采样频率、聚合函数和处理逻辑。