本文目录导读:

我来详细讲解如何使用Pandas进行数据分组重采样,包含多个实用案例。
基础环境准备
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# 创建示例数据
np.random.seed(42)
# 生成时间序列数据
dates = pd.date_range('2024-01-01', '2024-03-31', freq='H')
groups = ['A', 'B', 'C']
# 创建DataFrame
data = {
'timestamp': np.random.choice(dates, 1000),
'group': np.random.choice(groups, 1000),
'value': np.random.randn(1000) * 10 + 50,
'count': np.random.randint(1, 100, 1000)
}
df = pd.DataFrame(data)
df = df.sort_values('timestamp')
print("原始数据预览:")
print(df.head())
案例1:按组和时间重采样
1 按天重采样并计算均值
# 方法1:使用groupby和resample
df_daily_mean = (df.set_index('timestamp')
.groupby('group')
.resample('D')['value']
.mean()
.reset_index())
print("按天重采样(均值):")
print(df_daily_mean.head(10))
2 多种聚合函数组合
# 同时计算多个统计量
df_daily_stats = (df.set_index('timestamp')
.groupby('group')
.resample('D')['value']
.agg(['mean', 'std', 'min', 'max', 'count'])
.reset_index())
print("\n按天重采样(多统计量):")
print(df_daily_stats.head(10))
案例2:不同时间频率的重采样
# 3.1 按小时重采样
df_hourly = (df.set_index('timestamp')
.groupby('group')
.resample('H')['value']
.mean()
.fillna(0)
.reset_index())
print("按小时重采样:")
print(df_hourly.head())
# 3.2 按周重采样
df_weekly = (df.set_index('timestamp')
.groupby('group')
.resample('W')['value']
.mean()
.reset_index())
print("\n按周重采样:")
print(df_weekly.head())
# 3.3 按月重采样
df_monthly = (df.set_index('timestamp')
.groupby('group')
.resample('M')['value']
.mean()
.reset_index())
print("\n按月重采样:")
print(df_monthly)
案例3:多列重采样
# 对多列进行不同的聚合操作
df_multi = (df.set_index('timestamp')
.groupby('group')
.resample('D')
.agg({
'value': ['mean', 'std'],
'count': ['sum', 'mean']
})
.reset_index())
print("多列重采样:")
print(df_multi.head(10))
# 简化列名
df_multi.columns = ['_'.join(col).strip('_') for col in df_multi.columns.values]
print("\n简化列名后:")
print(df_multi.head())
案例4:向前向后填充
# 创建包含缺失值的数据
dates_missing = pd.date_range('2024-01-01', periods=20, freq='H')
groups_missing = ['A', 'B']
df_missing = pd.DataFrame({
'timestamp': np.random.choice(dates_missing, 30),
'group': np.random.choice(groups_missing, 30),
'value': np.random.randn(30) * 10 + 50
}).drop_duplicates(subset=['timestamp', 'group'])
print("原始缺失数据:")
print(df_missing.head())
# 重采样并填充缺失值
df_filled = (df_missing.set_index('timestamp')
.groupby('group')
.resample('H')['value']
.mean()
.fillna(method='ffill') # 向前填充
.reset_index())
print("\n填充后的数据:")
print(df_filled.head(10))
案例5:自定义重采样规则
# 自定义时间偏移
from pandas.tseries.offsets import DateOffset
# 每2天重采样
df_2day = (df.set_index('timestamp')
.groupby('group')
.resample('2D')['value']
.mean()
.reset_index())
print("每2天重采样:")
print(df_2day.head())
# 自定义聚合函数
def custom_agg(x):
return np.percentile(x, 75) - np.percentile(x, 25)
df_custom = (df.set_index('timestamp')
.groupby('group')
.resample('W')
.agg({
'value': ['mean', custom_agg],
'count': 'sum'
})
.reset_index())
print("\n自定义聚合函数:")
print(df_custom.head())
案例6:数据可视化
import matplotlib.pyplot as plt
# 准备可视化数据
plot_data = df.set_index('timestamp')
# 绘制不同组的时间序列
fig, axes = plt.subplots(3, 1, figsize=(12, 10))
for i, group in enumerate(groups):
group_data = plot_data[plot_data['group'] == group]
daily_mean = group_data.resample('D')['value'].mean()
axes[i].plot(daily_mean.index, daily_mean.values, label=f'Group {group}')
axes[i].set_title(f'Group {group} - Daily Mean')
axes[i].set_xlabel('Date')
axes[i].set_ylabel('Value')
axes[i].legend()
axes[i].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
案例7:窗口滚动重采样
# 滚动窗口统计
df_rolling = (df.set_index('timestamp')
.groupby('group')
.resample('D')['value']
.mean()
.reset_index())
# 计算7天滚动均值
df_rolling['rolling_mean_7d'] = (df_rolling.groupby('group')
['value']
.transform(lambda x: x.rolling(7, min_periods=1).mean()))
print("滚动窗口重采样:")
print(df_rolling.head(10))
完整实用示例
def analyze_time_series(df, timestamp_col, group_col, value_col,
resample_freq='D', agg_func='mean'):
"""
完整的时间序列分析函数
Parameters:
-----------
df : DataFrame
输入数据
timestamp_col : str
时间戳列名
group_col : str
分组列名
value_col : str
数值列名
resample_freq : str
重采样频率 ('D', 'W', 'M', 'H'等)
agg_func : str
聚合函数 ('mean', 'sum', 'std'等)
"""
# 设置时间索引
df_processed = df.set_index(timestamp_col)
# 分组重采样
result = (df_processed.groupby(group_col)
.resample(resample_freq)[value_col]
.agg(agg_func)
.reset_index())
# 添加统计信息
result.columns = [timestamp_col, group_col, value_col]
# 计算变化率
result['pct_change'] = (result.groupby(group_col)[value_col]
.transform(lambda x: x.pct_change() * 100))
# 计算累计和
result['cumsum'] = (result.groupby(group_col)[value_col]
.transform('cumsum'))
return result
# 使用示例
analysis_result = analyze_time_series(
df,
timestamp_col='timestamp',
group_col='group',
value_col='value',
resample_freq='D',
agg_func='mean'
)
print("完整分析结果:")
print(analysis_result.head(15))
性能优化技巧
# 10.1 使用分类变量加速
df['group'] = df['group'].astype('category')
# 10.2 批量处理多个频率
def multi_freq_resample(df, freq_list=['D', 'W', 'M']):
results = {}
for freq in freq_list:
result = (df.set_index('timestamp')
.groupby('group')
.resample(freq)['value']
.mean()
.reset_index())
results[freq] = result
return results
# 10.3 并行处理(使用多进程)
from joblib import Parallel, delayed
def parallel_resample(df, freq):
return (df.set_index('timestamp')
.groupby('group')
.resample(freq)['value']
.mean()
.reset_index())
# 执行并行重采样
freqs = ['D', 'W', 'M', 'Q']
results = Parallel(n_jobs=-1)(
delayed(parallel_resample)(df, freq) for freq in freqs
)
for freq, result in zip(freqs, results):
print(f"\n{freq}频率重采样结果:")
print(result.head())
主要要点:
- 基础流程:设置时间索引 → 分组 → 重采样 → 聚合
- 常用频率:H(小时)、D(天)、W(周)、M(月)、Q(季度)
- 聚合函数:mean、sum、std、min、max、count、自定义函数
- 缺失处理:ffill、bfill、fillna
- 性能优化:使用category类型、并行处理
这些案例覆盖了日常工作中最常见的分组重采样需求,可以根据实际场景灵活组合使用。