跳到主内容
研究主线模型诊断与稳定性 · 第14–19讲1/6模块导览 →
讲义

第14讲:回归模型不稳定性 (Regression Model Instability)

分析小样本、滚动窗口与结构突变造成的回归系数不稳定,展示重采样、CUSUM 和分段比较方法。

完成状态保存在当前浏览器,可随时取消。

阶段 3 · 研究主线 · 第14–19讲

模型诊断与稳定性

本模块要解决

  • 诊断结构突变、共线性、模型误设、残差与过拟合
  • 区分拟合优度和可泛化的预测能力

研究纪律

  • 验证集不得参与特征、窗口或阈值选择
  • 所有模型都要写明失效条件和结构突变监控

1. 回归不稳定性简介#

回归模型帮助我们理解变量之间的关系,但由于多种因素,其系数可能不稳定。本教程探讨三个主要原因:小样本偏差噪声、结构突变和多重共线性。


2. 小样本中的偏差噪声#

核心概念#

在小数据集中,随机噪声可能对回归系数产生不成比例的影响。随着样本量增大,系数会趋于稳定。

示例:随机噪声回归#

code
import numpy as np
import statsmodels.api as sm
import matplotlib.pyplot as plt

def linreg(X, Y):
    X = sm.add_constant(X)  # 添加截距项
    model = sm.OLS(Y, X).fit()
    return model.params[0], model.params[1]  # 截距, 斜率

# 生成20个随机数据点
np.random.seed(107)
small_data = np.random.randn(20)
xs_small = np.arange(20)
a, b = linreg(xs_small, small_data)

# 可视化
plt.scatter(xs_small, small_data, alpha=0.7)
plt.plot(xs_small, xs_small*b + a, 'r')
plt.title("小样本回归演示");

练习1#

生成1000个随机点观察系数变化:

code
large_data = np.random.randn(1000)
xs_large = np.arange(1000)
a_large, b_large = linreg(xs_large, large_data)
print(f"大样本斜率:{b_large:.4f}")

3. 结构突变(机制变化)#

核心概念#

当变量间关系发生突变时,模型在突变前后会失效。

示例:SPY价格结构突变#

code
import yfinance as yf

# 获取数据
data = yf.download('SPY', start='2003-01-01', end='2009-02-01')
prices = data['Close']

# 设置断点(约2007年6月)
breakpoint = 1200
pre_break = prices.iloc[:breakpoint]
post_break = prices.iloc[breakpoint:]

# 分段回归
X_full = np.arange(len(prices))
a_full, b_full = linreg(X_full, prices)

X_pre = np.arange(len(pre_break))
a_pre, b_pre = linreg(X_pre, pre_break)

X_post = np.arange(len(post_break))
a_post, b_post = linreg(X_post, post_break)

# 可视化
plt.figure(figsize=(10,6))
prices.plot(label='SPY价格')
plt.plot(prices.index, X_full*b_full + a_full, 'y', label='全段回归')
plt.plot(pre_break.index, X_pre*b_pre + a_pre, 'r', label='断点前')
plt.plot(post_break.index, X_post*b_post + a_post, 'r', label='断点后')
plt.legend();

练习2#

使用CUSUM检验结构突变:

code
from statsmodels.stats.diagnostic import breaks_cusumolsresid

full_model = sm.OLS(prices, sm.add_constant(X_full)).fit()
print(f"CUSUM检验p值:{breaks_cusumolsresid(full_model.resid)[1]:.2e}")

4. 多重共线性问题#

核心概念#

当预测变量高度相关时,微小数据变化会导致系数大幅波动。

示例:相关ETF分析#

code
# 获取三组数据
data = yf.download(['SPY', 'MDY', 'V'], start='2013-01-01', end='2015-06-01')['Close']

# 数据清洗
b1 = data['SPY'].dropna()
b2 = data['MDY'].dropna()
asset = data['V'].dropna()

# 计算相关系数
corr = b1.corr(b2)
print(f"SPY-MDY相关系数:{corr:.2f}")

# 多元回归函数
def multiple_linreg(Y, X1, X2):
    X = sm.add_constant(np.column_stack((X1, X2)))
    model = sm.OLS(Y, X).fit()
    return model.params

# 分时段回归
params1 = multiple_linreg(asset['2013':'2015'], b1['2013':'2015'], b2['2013':'2015'])
params2 = multiple_linreg(asset, b1, b2)

print(f"2013-2015年系数:SPY={params1[1]:.2f}, MDY={params1[2]:.2f}")
print(f"延长时段系数:SPY={params2[1]:.2f}, MDY={params2[2]:.2f}")

练习3#

计算方差膨胀因子(VIF):

code
from statsmodels.stats.outliers_influence import variance_inflation_factor

X = sm.add_constant(np.column_stack((b1, b2)))
vifs = [variance_inflation_factor(X, i) for i in range(1, X.shape[1])]
print(f"方差膨胀因子:{vifs}")

5. 解决方案#

  • 小样本问题:增加数据量或使用正则化

  • 结构突变:使用滚动窗口回归或突变检测

  • 多重共线性:删除相关变量或使用主成分分析(PCA)


6. 关键要点#

  1. 样本容量直接影响模型稳定性

  2. 警惕时间序列中的结构突变

  3. 检查预测变量间的相关性

  4. 使用统计检验验证模型假设

下一步建议:探索岭回归/Lasso回归等正则化方法,学习时间序列交叉验证技巧。