本文目录导读:

我来详细讲解Pandas中数据分组窗口的操作方法。
基础概念
分组窗口操作结合了 分组(groupby) 和 窗口(window) 两个概念,可以在每个组内进行滑动窗口计算。
准备工作
import pandas as pd
import numpy as np
# 创建示例数据
df = pd.DataFrame({
'group': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B'],
'date': pd.date_range('2024-01-01', periods=8, freq='D'),
'value': [10, 20, 15, 25, 30, 35, 28, 40]
})
print(df)
核心案例
案例1:分组滚动窗口(移动平均)
# 计算每个组内3天的移动平均值
df['rolling_avg'] = df.groupby('group')['value'].transform(
lambda x: x.rolling(window=3, min_periods=1).mean()
)
print("分组滚动平均:")
print(df)
案例2:分组扩展窗口
# 计算每个组内的累计平均值
df['expanding_mean'] = df.groupby('group')['value'].transform(
lambda x: x.expanding().mean()
)
print("\n分组累计平均:")
print(df)
案例3:分组指数加权窗口
# 指数加权移动平均,更重视近期数据
df['ewm_mean'] = df.groupby('group')['value'].transform(
lambda x: x.ewm(span=3, adjust=False).mean()
)
print("\n分组指数加权平均:")
print(df)
实用案例:时间序列分析
# 创建更真实的时间序列数据
dates = pd.date_range('2024-01-01', periods=20, freq='D')
sales_data = pd.DataFrame({
'store': ['A', 'B', 'C'] * 7,
'date': dates[:21],
'sales': np.random.randint(100, 500, 21)
}).sort_values(['store', 'date']).reset_index(drop=True)
print("原始数据:")
print(sales_data.head(10))
# 案例:计算每个店铺7天移动平均销售额
sales_data['sales_7d_avg'] = sales_data.groupby('store')['sales'].transform(
lambda x: x.rolling(window=7, min_periods=1).mean()
)
# 案例:计算每个店铺累计销售额
sales_data['cumulative_sales'] = sales_data.groupby('store')['sales'].transform(
lambda x: x.expanding().sum()
)
# 案例:计算销售额环比增长率
sales_data['growth_rate'] = sales_data.groupby('store')['sales'].transform(
lambda x: x.pct_change()
)
print("\n分析结果:")
print(sales_data)
高级应用:自定义窗口函数
# 自定义窗口计算
def custom_window_stats(series):
"""自定义窗口统计:返回窗口的最大值和最小值之差"""
return series.rolling(window=3).apply(lambda x: x.max() - x.min(), raw=False)
df['range_3d'] = df.groupby('group')['value'].transform(custom_window_stats)
print("自定义窗口函数结果:")
print(df)
窗口聚合操作
# 使用agg进行多个聚合计算
window_funcs = ['mean', 'sum', 'std', 'min', 'max']
result = df.groupby('group')['value'].apply(
lambda x: x.rolling(window=3, min_periods=1).agg(window_funcs)
)
print("\n多个聚合函数结果:")
print(result)
实战案例:股票数据分析
# 模拟股票数据
stock_data = pd.DataFrame({
'stock': ['AAPL', 'AAPL', 'AAPL', 'GOOGL', 'GOOGL', 'GOOGL'] * 5,
'date': pd.date_range('2024-01-01', periods=30, freq='D'),
'price': np.random.uniform(100, 200, 30)
}).sort_values(['stock', 'date']).reset_index(drop=True)
# 案例:计算每只股票的技术指标
result = stock_data.groupby('stock').agg({
'price': [
('5日移动均线', lambda x: x.rolling(5).mean()),
('10日移动均线', lambda x: x.rolling(10).mean()),
('5日波动率', lambda x: x.rolling(5).std()),
('20日累计收益', lambda x: x.rolling(20).apply(
lambda y: (y.iloc[-1] - y.iloc[0]) / y.iloc[0] * 100
))
]
})
print("\n股票技术分析:")
print(result)
性能优化建议
# 方法1:使用transform避免groupby后的索引问题
df['optimized_rolling'] = df.groupby('group')['value'].transform(
lambda x: x.rolling(3).mean()
)
# 方法2:对于大数据集,先排序再分组计算
df_sorted = df.sort_values(['group', 'date'])
df_sorted['rolling_avg'] = df_sorted.groupby('group')['value'].rolling(
3, min_periods=1
).mean().values
# 方法3:使用pd.Grouper进行时间分组
df_time = df.set_index('date')
weekly_rolling = df_time.groupby('group').rolling('7D')['value'].mean()
关键要点
-
窗口类型:
rolling(): 固定大小滑动窗口expanding(): 扩展窗口ewm(): 指数加权窗口
-
参数说明:
min_periods: 最少有效值数量window: 窗口大小on: 指定时间列
-
常用方法:
transform(): 保持原DataFrame形状apply(): 灵活的自定义函数agg(): 多个聚合函数
通过这些案例,你可以灵活运用Pandas进行各种分组窗口分析,根据实际需求选择合适的窗口类型和聚合函数。