第四讲:Engle-Granger两步法(上)——第一步,协整回归

好,咱们今天进入协整建模的核心环节。Engle-Granger两步法,说白了就是把一个复杂问题拆成两个简单步骤。第一步做什么?用OLS估计长期均衡关系。听起来是不是挺直接的?嗯,但这里面的门道可不少。

我个人习惯把EG两步法比作「先搭骨架,再填血肉」。第一步就是搭骨架——找到变量之间那个稳定的长期关系。你想想看,如果骨架都歪了,后面填再多的血肉也是白搭。

4.1 为什么要先做协整回归?

先问个问题:两个非平稳序列,直接做回归,不怕伪回归吗?

怕,当然怕。但这里有个关键点——如果它们真的存在协整关系,那么OLS估计出来的参数就是「超级一致」的。什么意思?就是说,即使变量是非平稳的,只要它们协整,OLS估计量的收敛速度比平稳序列还快。这是Stock在1987年证明的结论,我当年读到这篇论文时,说实话,挺震撼的。

所以,第一步协整回归的目的很明确:

  • 估计长期均衡系数 β
  • 提取残差序列,用于第二步检验
  • 为后续的误差修正模型提供基准

核心要点:协整回归不是普通的回归,它是在「非平稳」的土壤里寻找「平稳」的关系。OLS在这里扮演的角色,更像是一个探测器。

4.2 协整回归的数学表达

假设我们有两个时间序列 y_t 和 x_t,都是 I(1) 过程。那么长期均衡关系可以写成:

y_t = β₀ + β₁·x_t + ε_t

如果 y_t 和 x_t 真的协整,那么残差 ε_t 应该是平稳的,即 I(0)。

这里有个细节我特别想强调:回归方程中要不要加截距项? 我在项目中遇到过好几次,有人为了图省事直接跑不带截距的回归,结果残差序列怎么检验都不平稳。后来发现,是截距项缺失导致估计偏误。

我的建议是:默认加截距项。除非你有非常强的理论依据说长期均衡必须过原点,否则别省这个截距。

4.3 Python实现:从数据到回归

好,咱们直接上代码。我用的是 statsmodels 和 numpy,这两个库做协整回归足够了。

import numpy as np
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt

# 生成模拟数据:两个协整的 I(1) 序列
np.random.seed(42)
T = 200
# 共同随机趋势
common_trend = np.cumsum(np.random.normal(0, 1, T))
# y 和 x 围绕共同趋势波动
x = common_trend + np.random.normal(0, 0.5, T)
y = 2 + 0.8 * x + np.random.normal(0, 0.3, T)

# 第一步:协整回归
X = sm.add_constant(x)  # 加截距项
model = sm.OLS(y, X)
results = model.fit()

print(results.summary())

# 提取残差
residuals = results.resid

跑完这段代码,你会看到回归结果。重点关注几个指标:

  • 系数估计值:β₀ 和 β₁ 是否接近真实值(2 和 0.8)
  • :协整回归的 R² 通常很高,但这不代表模型好——因为变量本身有趋势
  • Durbin-Watson 统计量:如果接近 2,说明残差自相关不严重,这是个好信号

个人经验:我一般不会太纠结协整回归的 R² 值。有一次我帮客户做汇率分析,R² 高达 0.98,客户特别兴奋。我说别急,等第二步残差检验出来再说。结果残差非平稳,那个 0.98 就是个美丽的陷阱。

4.4 残差提取:关键中的关键

协整回归做完,最重要的产出不是系数,而是残差序列。为什么?因为第二步要用这个残差来检验协整关系是否存在。

残差的计算很简单:

# 计算残差
residuals = y - results.predict(X)

# 或者直接用 results.resid
# 可视化残差
plt.figure(figsize=(10, 4))
plt.plot(residuals, label='Residuals', color='navy')
plt.axhline(y=0, color='red', linestyle='--', alpha=0.5)
plt.title('协整回归残差序列')
plt.legend()
plt.show()

嗯,这里要注意一点:残差序列的均值应该接近 0。因为 OLS 回归保证了残差均值为 0,这是最小二乘法的性质。如果发现残差均值明显偏离 0,那说明回归可能有问题——比如遗漏了重要变量。

避坑指南:我曾经犯过一个错误——直接用原始数据做回归,忘了检查变量是否同阶单整。结果残差看起来挺平稳,但实际上是两个不同阶数的变量硬凑出来的假象。所以,在做协整回归之前,一定先确认所有变量都是 I(1) 的。

4.5 协整回归的SVG流程图

下面这张图,把第一步的整个逻辑串起来了。我建议你保存下来,做项目时对照着看。

EG两步法第一步:协整回归流程 输入 y_t, x_t (I(1)) OLS估计:y = β₀ + β₁x + ε 提取残差 ε̂_t = y_t - ŷ_t 输出:β̂₀, β̂₁, ε̂_t 关键检查点 ① 变量是否同阶单整? ② 是否加了截距项? ③ 残差均值是否≈0? ④ DW统计量是否接近2? ⑤ 系数符号是否符合 经济理论? 注意:残差序列将用于第二步的ADF检验

4.6 实际应用中的几个坑

做协整回归这么多年,我踩过的坑还真不少。挑几个典型的说说:

  1. 变量顺序问题:EG两步法对变量顺序敏感。你把 y 和 x 互换,估计出来的系数可能完全不同。我的建议是:根据经济理论确定哪个是因变量,哪个是自变量。
  2. 样本量太小:协整检验对样本量有要求。少于50个观测值,结果基本不可信。我一般要求至少100个观测值才敢做。
  3. 结构突变:如果样本期内发生了政策变化或金融危机,协整关系可能断裂。这时候需要分段检验,或者用 Gregory-Hansen 方法处理结构突变。

一句话总结:协整回归不是终点,而是起点。它的价值在于为第二步的残差检验提供「干净」的输入。残差质量直接决定协整检验的成败。

4.7 代码封装:写一个协整回归函数

为了方便复用,我习惯把协整回归封装成一个函数。这样每次做新项目时,直接调用就行。

def cointegrating_regression(y, x, add_constant=True):
    """
    执行Engle-Granger两步法的第一步:协整回归
    
    参数:
    y : array-like, 因变量
    x : array-like, 自变量
    add_constant : bool, 是否添加截距项
    
    返回:
    results : OLS回归结果对象
    residuals : 残差序列
    """
    if add_constant:
        X = sm.add_constant(x)
    else:
        X = x
    
    model = sm.OLS(y, X)
    results = model.fit()
    residuals = results.resid
    
    print("=" * 50)
    print("协整回归结果")
    print("=" * 50)
    print(f"样本量: {len(y)}")
    print(f"R²: {results.rsquared:.4f}")
    print(f"调整R²: {results.rsquared_adj:.4f}")
    print(f"DW统计量: {sm.stats.durbin_watson(residuals):.4f}")
    print("\n系数估计:")
    print(results.params)
    
    return results, residuals

# 使用示例
results, resid = cointegrating_regression(y, x)

这个函数我用了好几年,从外汇市场到股票配对交易,从宏观经济到能源价格分析,基本没出过问题。当然,前提是数据质量过关。

好了,第一步的内容就到这里。记住:协整回归的核心不是追求高 R²,而是得到可靠的残差序列。残差好不好,直接决定了第二步检验的成败。做项目时,多花点时间在第一步上,后面会省很多麻烦。


专注资料整理