如何在FOR循环回归中计算并存储每日残差?相关疑问
配对交易回归残差问题解答
嘿,针对你代码里的两个疑问,我来逐一给你理清:
问题1:reg._residues是不是真实Y与预测值的残差?
绝对不是。首先要明确:sklearn里的LinearRegression的_residues是个内部属性(以下划线开头,属于框架未公开的实现细节,不建议依赖),它代表的是所有训练样本残差的平方和——也就是$\sum_{i=1}^{n}(y_{真实} - y_{预测})^2$,是一个单一数值,而非每个样本对应的残差序列。
这就解释了为什么你用它做分布图时完全不符合正态/平稳特征:你其实在分析一个孤立值的分布(或者错误地重复使用这个值),根本不是每日的残差数据。如果要获取单样本残差,必须自己计算每个样本的真实值与预测值的差值。
问题2:怎么在循环里正确计算每日残差?
你的原代码在计算y_pred时犯了逻辑错误:每次循环都用了bank_matrix[['LDO.MI']][lookback:](也就是所有lookback之后的LDO数据)来预测,而不是对应当前循环步长的单一天的数据。下面是修正后的完整逻辑,同时提供两种计算残差的正确方式:
修正后的代码片段
import numpy as np import pandas as pd import matplotlib.pyplot as plt import pandas_datareader as pdr from sklearn.linear_model import LinearRegression from pandas.plotting import register_matplotlib_converters register_matplotlib_converters() import datetime tickers=['EXO.MI','LDO.MI'] end=datetime.date.today() gap=datetime.timedelta(days=650) start=end- gap Bank=pdr.get_data_yahoo(tickers,start=start,end=end) bank_matrix=Bank['Adj Close'] bank_matrix=bank_matrix.dropna() exor=bank_matrix['EXO.MI'] leonardo=bank_matrix['LDO.MI'] lookback=20 # 初始化存储列表,长度匹配有效数据 Hedge=[] Intercetta=[] Residuals=[] # 循环从lookback开始,对应第i天,用前lookback天的数据拟合 for i in range(lookback, len(exor)): # 准确截取前lookback天的训练数据:左闭右开,正好取lookback个样本 X_train = bank_matrix[['LDO.MI']].iloc[i-lookback:i] y_train = bank_matrix[['EXO.MI']].iloc[i-lookback:i] # 拟合回归模型 reg = LinearRegression().fit(X_train, y_train) # 存储截距和对冲系数(注意取标量,因为sklearn返回的是数组) Intercetta.append(reg.intercept_[0]) Hedge.append(reg.coef_[0][0]) # 方式1:用模型预测当天的LDO值,计算残差 X_today = bank_matrix[['LDO.MI']].iloc[i:i+1] y_pred_today = reg.predict(X_today)[0][0] y_true_today = exor.iloc[i] residual_today = y_true_today - y_pred_today # 方式2:手动计算预测值,结果和方式1完全一致 # y_pred_today_manual = reg.intercept_[0] + reg.coef_[0][0] * leonardo.iloc[i] # residual_today = y_true_today - y_pred_today_manual Residuals.append(residual_today) # 构建结果DataFrame,索引匹配有效日期 Regressione = pd.DataFrame({ 'Intercetta': Intercetta, 'Hedge': Hedge, 'Residuals': Residuals }, index=bank_matrix.index[lookback:])
关键修正点:
- 训练数据切片:用
iloc[i-lookback:i]准确获取前lookback天的样本,避免了原代码中切片逻辑的模糊性。 - 单日预测:每次循环只预测当前第i天的LDO值,保证残差是对应当天的真实值与预测值的差。
- 维度处理:
reg.intercept_和reg.coef_都是二维数组(因为sklearn要求输入是二维的),所以要通过[0]或[0][0]提取标量值,这也是你之前手动计算报错的核心原因——没有处理数组维度。
修改后你就能得到正确的每日残差序列,之后就可以正常分析它的正态性和平稳性,用于配对交易的策略开发了。
内容的提问来源于stack exchange,提问作者Polar
相关产品推荐
相关产品推荐

