使用pandas rolling.apply做滚动回归时报b未定义的PatsyError问题
问题产生原因
- pandas 的
rolling.apply()默认为逐列处理模式,传入回调函数的参数是仅包含单列数据的一维数组,不存在a、b两个字段,因此patsy解析公式时无法找到b变量,触发报错。 - 原有写法直接返回完整的回归拟合对象,不符合
rolling.apply()要求回调函数必须返回单个标量的规则,就算解决了变量识别问题也会触发后续报错。
解决方案
方案1:适配pandas 1.3.0及以上版本(推荐)
使用method='table'参数让rolling将完整的窗口数据以二维结构传入回调函数,同时明确指定需要提取的回归参数即可,示例代码如下:
import pandas as pd import numpy as np import statsmodels.formula.api as smf df = pd.DataFrame({'a':[1,3,5,7,4,5,6,4,7,8,9,1,3,5,7,4,5,6,4,7,8,9], 'b':[3,5,6,2,4,6,2,5,7,1,9,5,3,2,5,4,3,6,4,1,1,9]}) # 自定义滚动回归函数,可灵活返回任意你需要的回归指标 def roll_reg(window_data): # 将传入的二维数组转成带列名的DataFrame,供patsy识别变量 window_df = pd.DataFrame(window_data, columns=['a', 'b']) model = smf.ols('a ~ b', data=window_df).fit() # 此处可按需修改返回值,比如返回截距就写model.params['Intercept'],返回R方写model.rsquared return model.params['b'] # 调用rolling计算,method='table'表示传入完整窗口数据,raw=False保证传入数组结构 df['b_coef'] = df.rolling(10, method='table').apply(roll_reg, raw=False, axis=0)['a']
方案2:兼容全版本pandas的手动遍历写法
如果你的pandas版本较低不支持method='table'参数,可以手动遍历滚动窗口实现,灵活度更高也不存在版本依赖:
window_size = 10 coef_result = [] # 遍历所有有效窗口位置 for i in range(window_size, len(df)+1): # 截取当前窗口的DataFrame window_df = df.iloc[i-window_size:i, :] model = smf.ols('a ~ b', data=window_df).fit() coef_result.append(model.params['b']) # 把结果补全到和原数据长度一致,前window_size-1个窗口大小不足,填充为空 df['b_coef'] = [np.nan]*(window_size-1) + coef_result
如果需要同时返回多个回归参数,只需要修改返回逻辑,把每个窗口的多个指标存为字典/元组,最后统一转成DataFrame合并到原数据即可。
内容的提问来源于stack exchange,提问作者ℕʘʘḆḽḘ
相关产品推荐
相关产品推荐

