Skip to content

8.4 弱工具变量与诊断检验

"Weak instruments are worse than no instruments at all.""弱工具变量比没有工具变量更糟糕。"— Douglas Staiger & James Stock, 1997

当工具变量太"弱"时会发生什么?如何诊断和应对?


📌 本节概要

在本节中,我们将深入探讨:

  • 弱工具变量问题: 时的灾难性后果
  • Staiger & Stock (1997) 的 F > 10 经验法则
  • Stock & Yogo (2005) 的严格临界值
  • 弱 IV 的偏差方向:向 OLS 偏移
  • 过度识别检验:Sargan/Hansen J 检验
  • 内生性检验:Hausman 检验 / Durbin-Wu-Hausman 检验
  • 实用诊断清单
  • 所有检验的 Python 实现

🚨 弱工具变量问题

什么是弱工具变量?

回顾 2SLS 的第一阶段:

弱工具变量指的是 非常接近于零——即 的影响很微弱。

相关性条件要求 ,但即使 在统计意义上不为零,如果它很小,也会带来严重的问题。

为什么弱 IV 是灾难性的?

回忆 IV 估计量:

当分母 时,我们实际上是在除以一个接近零的数。这会导致:

1. 偏差(Bias)

即使 很小(排他性近似成立),当 时,比值 可以变得很大!

大白话:微小的排他性违反,在弱 IV 下会被放大成巨大的偏差。

2. 偏向 OLS

Bound, Jaeger & Baker (1995) 和 Staiger & Stock (1997) 证明了一个重要结论:

其中 是第一阶段 F 统计量。

含义

  • (强 IV):(无偏)
  • (弱 IV):(向 OLS 偏移!)
  • :2SLS 的偏差和 OLS 完全一样——做了 IV 等于白做!

3. 标准误膨胀

弱 IV 下,IV 估计量的方差急剧增大:

时,方差 →

4. 置信区间失效

  • 弱 IV 下,2SLS 估计量的分布不是正态分布(即使大样本)
  • 常规的 t 检验和置信区间不可信
  • 需要使用 Anderson-Rubin (1949) 等弱 IV 稳健推断方法

蒙特卡洛模拟:弱 IV 的灾难

python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from linearmodels.iv import IV2SLS

plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
sns.set_style("whitegrid")

np.random.seed(42)

def simulate_iv(n, pi1, n_sims=1000):
    """模拟不同强度工具变量下的 IV 估计"""
    beta_true = 3.0
    ols_estimates = []
    iv_estimates = []

    for _ in range(n_sims):
        U = np.random.normal(0, 1, n)
        Z = np.random.normal(0, 1, n)
        D = pi1 * Z + 0.8 * U + np.random.normal(0, 1, n)
        Y = 10 + beta_true * D + 2 * U + np.random.normal(0, 1, n)

        # OLS
        from numpy.linalg import lstsq
        X_ols = np.column_stack([np.ones(n), D])
        beta_ols = lstsq(X_ols, Y, rcond=None)[0][1]
        ols_estimates.append(beta_ols)

        # IV (Wald-like)
        cov_YZ = np.cov(Y, Z)[0, 1]
        cov_DZ = np.cov(D, Z)[0, 1]
        if abs(cov_DZ) > 1e-10:
            iv_estimates.append(cov_YZ / cov_DZ)

    return ols_estimates, iv_estimates

# 不同强度的 IV
pi1_values = [0.01, 0.1, 0.5, 2.0]
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

beta_true = 3.0

for idx, pi1 in enumerate(pi1_values):
    ax = axes[idx // 2][idx % 2]
    ols_est, iv_est = simulate_iv(500, pi1, n_sims=2000)

    # 计算近似 F 统计量
    approx_F = (pi1**2 * 500) / 1  # 简化的 F ≈ n * π₁²

    ax.hist(ols_est, bins=50, alpha=0.5, color='red', label='OLS', density=True)
    ax.hist(iv_est, bins=50, alpha=0.5, color='blue', label='IV/2SLS', density=True,
            range=(beta_true - 5, beta_true + 5))
    ax.axvline(x=beta_true, color='green', linewidth=2, linestyle='--', label=f'真实值 = {beta_true}')
    ax.set_title(f'π₁ = {pi1}(F ≈ {approx_F:.0f})', fontsize=13, fontweight='bold')
    ax.legend(fontsize=9)
    ax.set_xlim(beta_true - 5, beta_true + 5)

plt.suptitle('弱工具变量的蒙特卡洛模拟\n(工具变量越弱,IV 估计越不可靠)',
             fontsize=15, fontweight='bold')
plt.tight_layout()
plt.savefig('weak_iv_simulation.png', dpi=300, bbox_inches='tight')
plt.show()

print("观察:")
print("- π₁ = 0.01(极弱 IV):IV 的分布极其分散,几乎没有信息")
print("- π₁ = 0.1(弱 IV):IV 的分布虽然中心接近真实值,但方差很大")
print("- π₁ = 0.5(中等 IV):IV 表现开始变好")
print("- π₁ = 2.0(强 IV):IV 分布紧密集中在真实值附近")

📏 第一阶段 F 统计量

Staiger & Stock (1997) 的经验法则

问题:如何判断工具变量是否足够"强"?

Staiger & Stock (1997) 提出了一个简单的经验法则:

第一阶段 F 统计量是第一阶段回归中工具变量联合显著性的 F 检验统计量:

其中:

  • = 工具变量的数量
  • = 样本量
  • = 所有解释变量的数量
  • "unrestricted" = 包含 IV 的回归
  • "restricted" = 不包含 IV 的回归

直觉:F 统计量衡量的是"加入工具变量后,第一阶段回归的解释力提高了多少"。

判断标准

F 统计量判断建议
F > 100非常强的 IV放心使用
10 < F < 100可以接受结果可信,但需注意
F ≈ 10临界值需要额外检查
F < 10弱 IV⚠️ 结果不可信!
F < 5极弱 IV🚫 不要使用 IV!

Stock & Yogo (2005) 的严格临界值

Staiger & Stock 的 F > 10 只是一个粗略的经验法则。Stock & Yogo (2005) 提供了更严格的临界值,取决于:

  1. 内生变量的数量
  2. 工具变量的数量
  3. 可接受的偏差水平(相对于 OLS 偏差的比例)

Stock & Yogo 临界值表(单一内生变量,5% 显著性水平):

IV 数量10% 偏差15% 偏差20% 偏差25% 偏差
116.388.966.665.53
219.9311.598.757.25
322.3012.839.547.80
526.8715.0910.278.84
1026.8015.6011.499.35

解读

  • "10% 偏差"意味着 2SLS 偏差不超过 OLS 偏差的 10%
  • 例如:1 个 IV 时,要保证偏差不超过 OLS 的 10%,需要 F > 16.38
  • F > 10 大约对应 OLS 偏差的 15-20%

Python 实现:第一阶段 F 统计量

python
import numpy as np
import pandas as pd
import statsmodels.formula.api as smf
from linearmodels.iv import IV2SLS

np.random.seed(123)
n = 5000

# 生成数据
U = np.random.normal(0, 1, n)
Z = np.random.normal(0, 1, n)
X1 = np.random.normal(0, 1, n)

# 控制工具变量的强度
pi1 = 0.3  # 改变这个值来模拟不同强度

D = 1 + pi1 * Z + 0.5 * X1 + 0.8 * U + np.random.normal(0, 1, n)
Y = 5 + 3 * D + 0.3 * X1 + 2 * U + np.random.normal(0, 2, n)

df = pd.DataFrame({'Y': Y, 'D': D, 'Z': Z, 'X1': X1})

# --- 方法 1:手动计算第一阶段 F ---
# 第一阶段回归
first_stage_full = smf.ols('D ~ Z + X1', data=df).fit()
first_stage_restricted = smf.ols('D ~ X1', data=df).fit()

# F 统计量(Z 的贡献)
from scipy import stats

RSS_restricted = first_stage_restricted.ssr
RSS_full = first_stage_full.ssr
q = 1  # IV 的数量
n_obs = len(df)
k = first_stage_full.df_model

F_manual = ((RSS_restricted - RSS_full) / q) / (RSS_full / (n_obs - k - 1))

print("=" * 70)
print("第一阶段 F 统计量诊断")
print("=" * 70)
print(f"\n手动计算的 F 统计量: {F_manual:.2f}")
print(f"Z 的 t 统计量: {first_stage_full.tvalues['Z']:.2f}")
print(f"Z 的 t² (≈ F): {first_stage_full.tvalues['Z']**2:.2f}")
print(f"(单一 IV 时,F = t²)")

# 判断
if F_manual > 10:
    print(f"\n✅ F = {F_manual:.2f} > 10,工具变量足够强")
else:
    print(f"\n⚠️ F = {F_manual:.2f} < 10,存在弱工具变量问题!")

# --- 方法 2:使用 linearmodels 自动诊断 ---
iv_result = IV2SLS.from_formula('Y ~ 1 + X1 [D ~ Z]', data=df).fit(cov_type='robust')

print("\n" + "=" * 70)
print("linearmodels 自动诊断")
print("=" * 70)
print(iv_result.first_stage.diagnostics)

🔍 过度识别检验:Sargan / Hansen J 检验

动机

当工具变量数量多于内生变量数量时(过度识别),我们可以检验:

"所有的工具变量是否都满足排他性约束?"

直觉:如果有 个 IV 和 1 个内生变量,我们实际上有 个"多余"的识别条件(over-identifying restrictions)。这些多余的条件可以用来检验 IV 的有效性。

Sargan / Hansen J 检验

零假设:所有 IV 都是有效的(满足排他性约束)

备择假设:至少有一个 IV 是无效的

检验步骤

  1. 用 2SLS 估计模型,得到残差
  2. 对所有 IV 和外生变量回归,得到
  3. 检验统计量:
    • = IV 数量
    • = 内生变量数量
    • 自由度 = (过度识别的数量)

解读

  • p 值大 → 不拒绝 → IV 可能有效 ✅
  • p 值小 → 拒绝 → 至少一个 IV 可能无效 ❌

注意

  • 恰好识别时(),自由度 = 0,无法进行 J 检验
  • J 检验的功效有限——不拒绝 不代表 IV 一定有效
  • J 检验假设至少有一个 IV 是有效的

Python 实现

python
np.random.seed(456)
n = 5000

# 数据生成:多个 IV
U = np.random.normal(0, 1, n)
Z1 = np.random.normal(0, 1, n)
Z2 = np.random.normal(0, 1, n)
Z3 = np.random.normal(0, 1, n)

D = 1 + 0.5 * Z1 + 0.3 * Z2 + 0.4 * Z3 + 0.8 * U + np.random.normal(0, 1, n)
Y = 5 + 3 * D + 2 * U + np.random.normal(0, 2, n)

df_over = pd.DataFrame({
    'Y': Y, 'D': D, 'Z1': Z1, 'Z2': Z2, 'Z3': Z3
})

# 过度识别的 IV2SLS
iv_over = IV2SLS.from_formula('Y ~ 1 [D ~ Z1 + Z2 + Z3]', data=df_over)
iv_over_result = iv_over.fit(cov_type='robust')

print("=" * 70)
print("过度识别检验(Sargan / Hansen J 检验)")
print("=" * 70)
print(f"\nIV2SLS 估计结果:")
print(f"  D 的系数: {iv_over_result.params['D']:.4f}")
print(f"  标准误: {iv_over_result.std_errors['D']:.4f}")

# 手动 J 检验
residuals = iv_over_result.resids
Z_matrix = df_over[['Z1', 'Z2', 'Z3']].values
Z_with_const = np.column_stack([np.ones(n), Z_matrix])

from numpy.linalg import lstsq
beta_aux = lstsq(Z_with_const, residuals, rcond=None)[0]
residuals_fitted = Z_with_const @ beta_aux
R2_aux = 1 - np.sum((residuals - residuals_fitted)**2) / np.sum((residuals - residuals.mean())**2)
J_stat = n * R2_aux
df_J = 3 - 1  # 3 个 IV - 1 个内生变量
p_value_J = 1 - stats.chi2.cdf(J_stat, df_J)

print(f"\n手动 Sargan J 检验:")
print(f"  J 统计量: {J_stat:.4f}")
print(f"  自由度: {df_J}")
print(f"  p 值: {p_value_J:.4f}")

if p_value_J > 0.05:
    print(f"  ✅ p = {p_value_J:.4f} > 0.05,不拒绝 H₀,IV 可能有效")
else:
    print(f"  ❌ p = {p_value_J:.4f} < 0.05,拒绝 H₀,至少一个 IV 可能无效!")

# linearmodels 自动报告
print(f"\nlinearmodels 过度识别检验:")
print(iv_over_result.wooldridge_overid)

🔄 内生性检验:Hausman 检验

动机

一个自然的问题是:

"我到底需不需要用 IV? 真的是内生的吗?"

如果 实际上是外生的,那么 OLS 就是一致且有效的,IV 反而引入了不必要的方差。

Hausman 检验 / Durbin-Wu-Hausman (DWH) 检验

核心思想:比较 OLS 和 IV 的估计值。

  • 如果 是外生的:OLS 和 IV 都是一致的,但 OLS 更有效率
  • 如果 是内生的:只有 IV 是一致的

零假设 是外生的(不存在内生性)

备择假设 是内生的

检验统计量(Hausman 形式):

等价的回归方法(DWH 检验)

更实用的是回归版本的 Hausman 检验:

步骤

  1. 第一阶段回归:,得到残差
  2. 加入原回归:
  3. 检验

直觉未被 解释的部分。如果 ,说明这个"脏"的部分确实与 的误差相关——即 是内生的。

Python 实现

python
np.random.seed(789)
n = 5000

# --- 场景 1:D 是内生的 ---
U = np.random.normal(0, 1, n)
Z = np.random.normal(0, 1, n)
D_endo = 1 + 0.5 * Z + 0.8 * U + np.random.normal(0, 1, n)
Y_endo = 5 + 3 * D_endo + 2 * U + np.random.normal(0, 2, n)

df_endo = pd.DataFrame({'Y': Y_endo, 'D': D_endo, 'Z': Z})

# --- 场景 2:D 是外生的 ---
D_exo = 1 + 0.5 * Z + np.random.normal(0, 1, n)
Y_exo = 5 + 3 * D_exo + 2 * U + np.random.normal(0, 2, n)
# 注意:U 影响 Y 但不影响 D → D 是外生的

df_exo = pd.DataFrame({'Y': Y_exo, 'D': D_exo, 'Z': Z})

def hausman_test_regression(df, formula_first='D ~ Z', formula_second='Y ~ D'):
    """回归版 Hausman 检验(DWH)"""
    # 第一阶段
    first_stage = smf.ols(formula_first, data=df).fit()
    df_temp = df.copy()
    df_temp['v_hat'] = first_stage.resid

    # 扩展回归
    augmented = smf.ols(f'{formula_second} + v_hat', data=df_temp).fit()

    return {
        'delta': augmented.params['v_hat'],
        't_stat': augmented.tvalues['v_hat'],
        'p_value': augmented.pvalues['v_hat'],
        'reject': augmented.pvalues['v_hat'] < 0.05
    }

print("=" * 70)
print("Hausman / DWH 内生性检验")
print("=" * 70)

# 场景 1:内生
print("\n--- 场景 1:D 是内生的 ---")
result1 = hausman_test_regression(df_endo)
print(f"  δ̂ (v_hat 系数): {result1['delta']:.4f}")
print(f"  t 统计量: {result1['t_stat']:.4f}")
print(f"  p 值: {result1['p_value']:.6f}")
if result1['reject']:
    print(f"  ❌ 拒绝 H₀:D 是内生的,需要使用 IV!")
else:
    print(f"  ✅ 不拒绝 H₀:D 可能是外生的,OLS 即可")

# 场景 2:外生
print("\n--- 场景 2:D 是外生的 ---")
result2 = hausman_test_regression(df_exo)
print(f"  δ̂ (v_hat 系数): {result2['delta']:.4f}")
print(f"  t 统计量: {result2['t_stat']:.4f}")
print(f"  p 值: {result2['p_value']:.6f}")
if result2['reject']:
    print(f"  ❌ 拒绝 H₀:D 是内生的,需要使用 IV!")
else:
    print(f"  ✅ 不拒绝 H₀:D 可能是外生的,OLS 即可")

# 使用 linearmodels 的内生性检验
print("\n" + "=" * 70)
print("linearmodels 的 Wu-Hausman 检验")
print("=" * 70)

iv_endo = IV2SLS.from_formula('Y ~ 1 [D ~ Z]', data=df_endo).fit()
iv_exo = IV2SLS.from_formula('Y ~ 1 [D ~ Z]', data=df_exo).fit()

print("\n场景 1(内生):")
print(iv_endo.wu_hausman())
print("\n场景 2(外生):")
print(iv_exo.wu_hausman())

📋 IV 诊断清单

实用的 IV 分析流程

┌─────────────────────────────────────┐
│  Step 1: 论证 IV 的有效性           │
│  (经济学直觉 + 制度知识)          │
│  - 排他性约束合理吗?               │
│  - 独立性条件可信吗?               │
└──────────────┬──────────────────────┘

┌─────────────────────────────────────┐
│  Step 2: 检验相关性                  │
│  第一阶段 F > 10 ?                 │
│  (Stock & Yogo 临界值)               │
│  - F > 10: ✅ 继续                  │
│  - F < 10: ⚠️ 弱 IV 问题!         │
└──────────────┬──────────────────────┘

┌─────────────────────────────────────┐
│  Step 3: 内生性检验                  │
│  Hausman / DWH 检验                  │
│  - 拒绝 H₀: 需要 IV                │
│  - 不拒绝 H₀: OLS 可能就够         │
└──────────────┬──────────────────────┘

┌─────────────────────────────────────┐
│  Step 4: 过度识别检验                │
│  Sargan / Hansen J 检验              │
│  (仅当 IV 数 > 内生变量数时)       │
│  - 不拒绝 H₀: IV 可能有效          │
│  - 拒绝 H₀: 至少一个 IV 有问题     │
└──────────────┬──────────────────────┘

┌─────────────────────────────────────┐
│  Step 5: 报告和解释                  │
│  - 2SLS 估计值和标准误              │
│  - LATE 的解释                      │
│  - 稳健性检验                        │
└─────────────────────────────────────┘

完整的诊断 Python 函数

python
from linearmodels.iv import IV2SLS
from scipy import stats

def iv_diagnostics(df, dep_var, endog_var, instruments, exog_vars=None):
    """
    全面的 IV 诊断工具

    Parameters
    ----------
    df : DataFrame
    dep_var : str, 因变量名
    endog_var : str, 内生变量名
    instruments : list of str, 工具变量名
    exog_vars : list of str, 外生控制变量名(可选)
    """

    print("=" * 70)
    print("工具变量(IV/2SLS)全面诊断报告")
    print("=" * 70)

    # 构建公式
    if exog_vars:
        exog_str = ' + '.join(exog_vars)
        iv_str = ' + '.join(instruments)
        formula = f'{dep_var} ~ 1 + {exog_str} [{endog_var} ~ {iv_str}]'
        ols_formula = f'{dep_var} ~ {endog_var} + {exog_str}'
        fs_formula = f'{endog_var} ~ {iv_str} + {exog_str}'
    else:
        iv_str = ' + '.join(instruments)
        formula = f'{dep_var} ~ 1 [{endog_var} ~ {iv_str}]'
        ols_formula = f'{dep_var} ~ {endog_var}'
        fs_formula = f'{endog_var} ~ {iv_str}'

    # --- 1. OLS 估计 ---
    print("\n📊 1. OLS 估计(参考)")
    print("-" * 50)
    ols_result = smf.ols(ols_formula, data=df).fit()
    print(f"  OLS 系数 ({endog_var}): {ols_result.params[endog_var]:.4f}")
    print(f"  标准误: {ols_result.bse[endog_var]:.4f}")
    print(f"  p 值: {ols_result.pvalues[endog_var]:.6f}")

    # --- 2. 第一阶段 ---
    print(f"\n🔧 2. 第一阶段回归:{endog_var} ~ instruments")
    print("-" * 50)
    fs_result = smf.ols(fs_formula, data=df).fit()
    for iv in instruments:
        print(f"  {iv}: 系数={fs_result.params[iv]:.4f}, t={fs_result.tvalues[iv]:.2f}, p={fs_result.pvalues[iv]:.6f}")

    # F 统计量
    if len(instruments) == 1:
        F_stat = fs_result.tvalues[instruments[0]] ** 2
    else:
        F_stat = fs_result.fvalue

    print(f"\n  第一阶段 F 统计量: {F_stat:.2f}")
    if F_stat > 10:
        print(f"  ✅ F = {F_stat:.2f} > 10 → 工具变量足够强")
    else:
        print(f"  ⚠️ F = {F_stat:.2f} < 10 → 弱工具变量警告!")

    # --- 3. IV/2SLS 估计 ---
    print(f"\n📈 3. IV/2SLS 估计")
    print("-" * 50)
    iv_result = IV2SLS.from_formula(formula, data=df).fit(cov_type='robust')
    print(f"  IV 系数 ({endog_var}): {iv_result.params[endog_var]:.4f}")
    print(f"  标准误: {iv_result.std_errors[endog_var]:.4f}")
    print(f"  p 值: {iv_result.pvalues[endog_var]:.6f}")
    ci = iv_result.conf_int()
    print(f"  95% CI: [{ci.loc[endog_var, 'lower']:.4f}, {ci.loc[endog_var, 'upper']:.4f}]")

    # --- 4. 内生性检验 ---
    print(f"\n🔍 4. 内生性检验 (Wu-Hausman)")
    print("-" * 50)
    try:
        wh = iv_result.wu_hausman()
        print(f"  Wu-Hausman 统计量: {wh.stat:.4f}")
        print(f"  p 值: {wh.pval:.6f}")
        if wh.pval < 0.05:
            print(f"  ❌ 拒绝 H₀ (p < 0.05):D 是内生的,需要 IV")
        else:
            print(f"  ✅ 不拒绝 H₀ (p > 0.05):D 可能是外生的")
    except Exception as e:
        print(f"  无法计算: {e}")

    # --- 5. 过度识别检验 ---
    if len(instruments) > 1:
        print(f"\n📏 5. 过度识别检验 (Sargan/Hansen J)")
        print("-" * 50)
        try:
            overid = iv_result.wooldridge_overid
            print(f"  J 统计量: {overid.stat:.4f}")
            print(f"  p 值: {overid.pval:.6f}")
            print(f"  自由度: {len(instruments) - 1}")
            if overid.pval > 0.05:
                print(f"  ✅ 不拒绝 H₀ (p > 0.05):IV 可能有效")
            else:
                print(f"  ❌ 拒绝 H₀ (p < 0.05):至少一个 IV 可能无效!")
        except Exception as e:
            print(f"  无法计算: {e}")
    else:
        print(f"\n📏 5. 过度识别检验")
        print("-" * 50)
        print(f"  (恰好识别,无法进行 J 检验)")

    # --- 6. 汇总 ---
    print(f"\n📋 6. 汇总比较")
    print("-" * 50)
    print(f"  {'方法':<15} {'系数':<12} {'标准误':<12}")
    print(f"  {'OLS':<15} {ols_result.params[endog_var]:<12.4f} {ols_result.bse[endog_var]:<12.4f}")
    print(f"  {'IV/2SLS':<15} {iv_result.params[endog_var]:<12.4f} {iv_result.std_errors[endog_var]:<12.4f}")
    print(f"  {'差异':<15} {iv_result.params[endog_var] - ols_result.params[endog_var]:<12.4f}")

    return iv_result, ols_result

# 使用示例
np.random.seed(2024)
n = 5000
U = np.random.normal(0, 1, n)
Z1 = np.random.normal(0, 1, n)
Z2 = np.random.normal(0, 1, n)
D = 1 + 0.5 * Z1 + 0.3 * Z2 + 0.8 * U + np.random.normal(0, 1, n)
Y = 5 + 3 * D + 2 * U + np.random.normal(0, 2, n)

df_diag = pd.DataFrame({'Y': Y, 'D': D, 'Z1': Z1, 'Z2': Z2})

iv_result, ols_result = iv_diagnostics(
    df_diag,
    dep_var='Y',
    endog_var='D',
    instruments=['Z1', 'Z2']
)

⚠️ 弱 IV 的应对策略

策略 1:寻找更强的工具变量

这是最根本的解决方案。一个好的 IV 应该:

  • 与处理变量有强烈的相关性
  • 背后有清晰的理论机制

策略 2:Anderson-Rubin (AR) 检验

AR 检验在弱 IV 下仍然有效:

其中 的投影矩阵。

python
# Anderson-Rubin 置信区间
# linearmodels 提供了 AR 检验
print("\nAnderson-Rubin 检验(弱 IV 稳健):")
try:
    ar_test = iv_result.anderson_rubin()
    print(f"  AR 统计量: {ar_test.stat:.4f}")
    print(f"  p 值: {ar_test.pval:.6f}")
except Exception as e:
    print(f"  {e}")

策略 3:LIML 估计量

**有限信息最大似然估计(LIML)**在弱 IV 下比 2SLS 有更小的偏差:

python
from linearmodels.iv import IVLIML

liml_result = IVLIML.from_formula('Y ~ 1 [D ~ Z1 + Z2]', data=df_diag).fit()
print("\nLIML 估计:")
print(f"  D 的系数: {liml_result.params['D']:.4f}")
print(f"  标准误: {liml_result.std_errors['D']:.4f}")

策略 4:多个弱 IV 合并

如果有多个单独很弱但联合起来足够强的 IV,可以合并使用。但要注意 Many Instruments 偏差。


📝 本节要点

  1. 弱工具变量)会导致 2SLS 偏向 OLS、标准误膨胀、置信区间失效
  2. Staiger & Stock 法则:第一阶段 ;更严格用 Stock & Yogo 临界值
  3. Sargan/Hansen J 检验:检验过度识别约束(多 IV 时可用)
  4. Hausman/DWH 检验:检验是否真的需要 IV
  5. 弱 IV 应对:AR 检验(稳健推断)、LIML(更小偏差)、寻找更强 IV
  6. 始终报告完整的诊断结果——这是 IV 论文可信度的基石

下一节8.5 经典案例与 Python 实现 — 用 Python 复现 Angrist & Krueger (1991) 和 Card (1995) 的经典研究。

基于 MIT 许可证发布。内容版权归作者所有。