本文目录导读:

我来详细讲解如何使用Pandas进行数据分组滞后(GroupBy Shift)操作,这是时间序列分析和面板数据处理中非常常见的需求。
基础分组滞后操作
基本语法
import pandas as pd
# 创建示例数据
df = pd.DataFrame({
'group': ['A', 'A', 'A', 'B', 'B', 'B'],
'value': [1, 2, 3, 4, 5, 6],
'date': pd.date_range('2024-01-01', periods=6)
})
# 分组后计算滞后值
df['value_lag1'] = df.groupby('group')['value'].shift(1)
df['value_lag2'] = df.groupby('group')['value'].shift(2)
完整案例:销售数据滞后分析
案例场景
分析不同产品的销售额滞后效应,计算前一天和前两天的销售额。
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-01-10', freq='D')
products = ['产品A', '产品B', '产品C']
data = []
for product in products:
for date in dates:
data.append({
'产品': product,
'日期': date,
'销售额': np.random.randint(100, 1000)
})
df_sales = pd.DataFrame(data)
print("原始数据:")
print(df_sales.head(10))
计算多种滞后值
# 按产品分组,计算滞后1天、2天和3天的销售额
df_sales = df_sales.sort_values(['产品', '日期'])
df_sales['销售-前一天'] = df_sales.groupby('产品')['销售额'].shift(1)
df_sales['销售-前两天'] = df_sales.groupby('产品')['销售额'].shift(2)
df_sales['销售-前三天'] = df_sales.groupby('产品')['销售额'].shift(3)
# 计算环比变化率
df_sales['环比变化率'] = (df_sales['销售额'] - df_sales['销售-前一天']) / df_sales['销售-前一天'] * 100
print("\n添加滞后值后的数据:")
print(df_sales.head(15))
多列同时滞后
# 创建包含多个指标的数据
df_multi = pd.DataFrame({
'group': ['A', 'A', 'A', 'B', 'B', 'B'],
'sales': [100, 150, 200, 300, 250, 350],
'profit': [20, 30, 40, 60, 50, 70],
'cost': [80, 120, 160, 240, 200, 280]
})
# 同时对多列进行滞后
cols_to_lag = ['sales', 'profit', 'cost']
lag_periods = 1
for col in cols_to_lag:
df_multi[f'{col}_lag{lag_periods}'] = df_multi.groupby('group')[col].shift(lag_periods)
print("\n多列滞后数据:")
print(df_multi)
多层级分组滞后
# 多层级分组数据
df_multi_group = pd.DataFrame({
'region': ['北', '北', '北', '南', '南', '南', '东', '东', '东'],
'product': ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C'],
'price': [100, 120, 90, 110, 130, 95, 105, 125, 88],
'date': pd.date_range('2024-01-01', periods=9)
})
# 按地区和产品双分组
df_multi_group['price_lag'] = df_multi_group.groupby(['region', 'product'])['price'].shift(1)
print("\n多层级分组滞后:")
print(df_multi_group)
固定窗口滚动滞后
# 滚动窗口计算
df_rolling = pd.DataFrame({
'group': ['A'] * 10 + ['B'] * 10,
'value': range(1, 21),
'date': pd.date_range('2024-01-01', periods=20)
})
# 定义函数计算滚动统计
def rolling_stats(group):
return group.sort_values('date').rolling(window=3).agg({
'value': ['mean', 'std', 'min', 'max']
})
# 应用分组滚动
result = df_rolling.groupby('group').apply(
lambda x: x.set_index('date').rolling('3D').mean()
)
print("\n滚动窗口统计:")
print(result.head(10))
实用的数据分析案例
股票收益率分析
# 模拟股票数据
stocks = ['AAPL', 'GOOGL', 'MSFT']
dates = pd.date_range('2024-01-01', '2024-01-20', freq='D')
stock_data = []
for stock in stocks:
price = 100
for date in dates:
price *= (1 + np.random.normal(0, 0.02))
stock_data.append({
'股票': stock,
'日期': date,
'价格': round(price, 2)
})
df_stock = pd.DataFrame(stock_data)
df_stock = df_stock.sort_values(['股票', '日期'])
# 计算收益率和滞后收益率
df_stock['收益率'] = df_stock.groupby('股票')['价格'].pct_change() * 100
df_stock['收益-前一天'] = df_stock.groupby('股票')['收益率'].shift(1)
df_stock['收益-前两天'] = df_stock.groupby('股票')['收益率'].shift(2)
print("\n股票收益率分析:")
print(df_stock.head(15))
滞后值填充技巧
# 处理缺失值
df_na = pd.DataFrame({
'group': ['A', 'A', 'A', 'A', 'B', 'B', 'B'],
'value': [10, np.nan, 30, 40, 50, np.nan, 70],
'date': pd.date_range('2024-01-01', periods=7)
})
# 向前填充缺失值后再计算滞后
df_na['value_filled'] = df_na.groupby('group')['value'].fillna(method='ffill')
df_na['value_lag'] = df_na.groupby('group')['value_filled'].shift(1)
print("\n处理缺失值后的滞后:")
print(df_na)
性能优化技巧
# 大数据集处理优化
import time
# 创建大数据集
big_data = pd.DataFrame({
'group': np.random.choice(range(1000), 100000),
'value': np.random.randn(100000),
'date': pd.date_range('2024-01-01', periods=100000, freq='H')
})
# 优化方法1:设置索引后再分组
start_time = time.time()
result1 = big_data.set_index('date').groupby('group')['value'].shift(1)
print(f"方法1耗时: {time.time() - start_time:.3f}秒")
# 优化方法2:使用transform函数
start_time = time.time()
result2 = big_data.groupby('group')['value'].transform(
lambda x: x.shift(1)
)
print(f"方法2耗时: {time.time() - start_time:.3f}秒")
常见问题及解决方案
-
数据未排序导致的错误
# 正确的做法:先排序再分组 df_sorted = df.sort_values(['group', 'date']) df_sorted['lag'] = df_sorted.groupby('group')['value'].shift(1) -
多列不同滞后周期
# 定义滞后配置 lag_config = { 'sales': 1, 'profit': 2, 'cost': 3 }
for col, periods in lag_config.items(): df[f'{col}_lag{periods}'] = df.groupby('group')[col].shift(periods)
##
使用Pandas进行分组滞后操作的核心要点:
1. **先排序**:确保按分组列和时间列排序
2. **使用groupby+shift**:这是最直接的方法
3. **注意数据类型**:确保时间是datetime类型
4. **处理缺失值**:合理填充或处理NA值
5. **性能优化**:大数据集考虑使用transform
这些技巧在金融数据分析、销售预测、时间序列研究等领域非常实用。