You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中基于年份的Rolling Regression实现及window参数设置问题

基于年份的滚动回归实现方案

你的核心问题是RollingOLS默认的window参数是按行计数,而非关联Year变量的时间窗口,同时未考虑数据的ID分组逻辑,导致回归结果不符合需求。以下是针对性的解决方法:

数据预处理

首先确保数据按ID和Year升序排列,保证每个个体的时间序列顺序正确:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import statsmodels.api as sm
from statsmodels.regression.rolling import RollingOLS

d1 = {'ID': [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6], 
      'Earnings': [100, 200, 400, 250, 300, 350, 400, 550, 700, 259, 300, 350, 270, 450, 340, 570, 340, 340], 
      'WC': [20, 40, 35, 55, 60, 65, 30, 28, 32, 45, 60, 52, 23, 54, 45, 87, 54, 65], 
      'Year': [1995, 1996, 1997, 1996, 1997, 1998, 1995, 1997, 1998, 1996, 1997, 1998, 1995, 1997, 1998, 1996, 1997, 1998], 
      'F1_Earnings': [120, 220, 420, 280, 530, 670, 780, 210, 950, 100, 120, 430, 780, 210, 950, 100, 120, 430]}

df1 = pd.DataFrame(data=d1)
# 按ID和年份排序,保证时间序列顺序
df1 = df1.sort_values(['ID', 'Year']).reset_index(drop=True)

方法一:按ID分组的2年滚动回归

针对每个个体(ID)独立做2年窗口的滚动回归,适合个体间数据独立的场景:

def rolling_reg_by_id(group):
    # 添加回归常数项,statsmodels默认不含截距
    X = sm.add_constant(group[['Earnings', 'WC']])
    y = group['F1_Earnings']
    # 窗口设为2,因已按年份排序,每行对应一年,window=2即代表2年数据
    rols = RollingOLS(y, X, window=2)
    rres = rols.fit()
    return rres.params

# 按ID分组执行滚动回归
rolling_params = df1.groupby('ID', group_keys=False).apply(rolling_reg_by_id)
print(rolling_params)

补充:严格连续年份窗口

如果要求必须使用连续的2年数据(跳过缺失年份的观测),需先补全每个ID的所有年份:

# 生成所有ID和年份的组合
all_id_year = pd.MultiIndex.from_product([df1['ID'].unique(), df1['Year'].unique()], names=['ID', 'Year'])
# 补全缺失年份,缺失值填充为NaN
df_full = df1.set_index(['ID', 'Year']).reindex(all_id_year).reset_index()

# 再次执行分组滚动回归,自动忽略含NaN的窗口
rolling_params_full = df_full.groupby('ID', group_keys=False).apply(rolling_reg_by_id)
print(rolling_params_full.dropna())

方法二:全局时间窗口回归

若需求是用所有个体的最近2年数据做回归(比如用1997-1998年所有数据预测1998年的F1_Earnings),可使用时间索引的滚动窗口:

# 将年份转为datetime类型,支持时间窗口计算
df1['Year_dt'] = pd.to_datetime(df1['Year'], format='%Y')
df_time = df1.set_index('Year_dt')

def reg_func(window):
    X_win = sm.add_constant(window[['Earnings', 'WC']])
    y_win = window['F1_Earnings']
    model = sm.OLS(y_win, X_win).fit()
    return pd.Series(model.params, index=['const', 'Earnings', 'WC'])

# 2年时间窗口,至少需要2个观测值才执行回归
rolling_params_global = df_time.rolling(window='2Y', min_periods=2).apply(reg_func, raw=False)
print(rolling_params_global.dropna())

关键注意点

  1. 原代码无效的核心原因:直接用window=2是按行取数,未关联Year变量和ID分组,混合了不同个体、不同年份的数据。
  2. 常数项:RollingOLS默认不含截距,必须用sm.add_constant()添加,否则回归结果会缺失截距项。
  3. 窗口逻辑:按ID分组时,window=2对应2行(即2年)数据;全局时间窗口则直接用时间字符串定义窗口范围。

内容的提问来源于stack exchange,提问作者ChurrrT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 13:27:24