Skip to content

12.5 高级主题与最新进展

"Double machine learning combines the flexibility of ML with the rigor of econometrics.""双重机器学习结合了机器学习的灵活性和计量经济学的严谨性。"— Victor Chernozhukov, MIT Economist (MIT经济学家)

从Causal Forest到前沿方法:Double ML、GRF与深度学习

难度前沿研究


本节目标

完成本节后,你将能够:

  • 理解Double/Debiased Machine Learning (DML)框架
  • 掌握Generalized Random Forests (GRF)
  • 了解Causal Forest的扩展与变体
  • 探索深度学习在因果推断中的应用
  • 掌握最新研究方向和前沿方法

Double/Debiased Machine Learning (DML)

核心思想

Chernozhukov et al. (2018) 提出的框架:结合机器学习和因果推断

问题:机器学习模型(如Lasso, Random Forest)有正则化偏差

例子

python
# Lasso回归
Y = β₀ + β₁·T + β₂·X + ε

# Lasso会缩小所有系数(包括β₁)
# 导致处理效应估计有偏!

DML的解决方案

  1. 样本分割(Cross-fitting)
  2. Neyman正交化(去除混杂变量的影响)
  3. 无偏估计处理效应

数学框架

目标:估计 (处理效应)在模型中:

其中 是高维协变量的复杂函数(可以用ML估计)。

关键洞察:即使 有偏差,我们可以通过正交化得到 的无偏估计。

Neyman正交条件

其中 评分函数(score function), 是nuisance parameters。

对于CATE

其中:

  • :结果回归
  • :倾向得分

Python实现:DML + Causal Forest

python
from econml.dml import CausalForestDML
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
import numpy as np
import pandas as pd

# 生成数据(与之前相同)
np.random.seed(789)
n = 5000

# 协变量
X1 = np.random.uniform(0, 1, n)
X2 = np.random.uniform(0, 1, n)
X3 = np.random.normal(0, 1, n)
X4 = np.random.binomial(1, 0.5, n)

X = np.column_stack([X1, X2, X3, X4])

# 混杂变量(影响处理和结果)
confounding = X1 + X2

# 处理分配(非随机,受混杂影响)
propensity = 1 / (1 + np.exp(-(-1 + 2 * confounding)))
T = np.random.binomial(1, propensity)

# 真实CATE
true_tau = 5 + 10 * X1 - 5 * X2

# 结果变量(受混杂影响)
Y0 = 10 + 3 * confounding + 2 * X3 + np.random.normal(0, 1, n)
Y = Y0 + T * true_tau

print("=" * 70)
print("Double ML + Causal Forest")
print("=" * 70)

# DML with Causal Forest
dml_cf = CausalForestDML(
    # 第一阶段模型(估计E[Y|X,D]和P(D=1|X))
    model_y=RandomForestRegressor(n_estimators=100, random_state=42),
    model_t=RandomForestClassifier(n_estimators=100, random_state=42),
    # Causal Forest超参数
    n_estimators=2000,
    min_samples_leaf=10,
    max_depth=None,
    random_state=42
)

# 训练
dml_cf.fit(Y, T, X=X)

# 预测CATE
tau_dml = dml_cf.effect(X)
tau_interval_dml = dml_cf.effect_interval(X, alpha=0.05)

print(f"DML估计的ATE: {tau_dml.mean():.3f}")
print(f"真实的ATE: {true_tau.mean():.3f}")

# 评估
from sklearn.metrics import r2_score, mean_squared_error
r2_dml = r2_score(true_tau, tau_dml)
mse_dml = mean_squared_error(true_tau, tau_dml)

print(f"\nCATE预测性能:")
print(f"  R²: {r2_dml:.3f}")
print(f"  MSE: {mse_dml:.3f}")

# 对比:标准Causal Forest(无DML)
from econml.grf import CausalForest
cf_standard = CausalForest(n_estimators=2000, random_state=42)
cf_standard.fit(X, T.reshape(-1, 1), Y)
tau_standard = cf_standard.predict(X)

r2_standard = r2_score(true_tau, tau_standard)

print(f"\n对比:")
print(f"  DML + CF R²: {r2_dml:.3f}")
print(f"  标准CF R²: {r2_standard:.3f}")
print(f"  提升: {(r2_dml - r2_standard) / r2_standard * 100:.1f}%")

DML的优势

  1. 去偏差:即使第一阶段模型有正则化偏差,最终估计仍然无偏
  2. 高维适应:可以用任何ML方法估计nuisance functions
  3. 理论保证-一致性和渐近正态性
  4. 灵活性:适用于多种因果参数(ATE, CATE, LATE等)

可视化对比

python
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# 左图:DML
axes[0].scatter(true_tau, tau_dml, alpha=0.3, s=15)
axes[0].plot([true_tau.min(), true_tau.max()],
             [true_tau.min(), true_tau.max()],
             'r--', linewidth=2)
axes[0].set_xlabel('真实CATE', fontsize=12)
axes[0].set_ylabel('预测CATE', fontsize=12)
axes[0].set_title(f'DML + Causal Forest (R² = {r2_dml:.3f})',
                  fontsize=13, fontweight='bold')
axes[0].grid(True, alpha=0.3)

# 右图:标准CF
axes[1].scatter(true_tau, tau_standard, alpha=0.3, s=15)
axes[1].plot([true_tau.min(), true_tau.max()],
             [true_tau.min(), true_tau.max()],
             'r--', linewidth=2)
axes[1].set_xlabel('真实CATE', fontsize=12)
axes[1].set_ylabel('预测CATE', fontsize=12)
axes[1].set_title(f'标准Causal Forest (R² = {r2_standard:.3f})',
                  fontsize=13, fontweight='bold')
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

Generalized Random Forests (GRF)

从Causal Forest到GRF

Athey, Tibshirani, & Wager (2019) 将Causal Forest推广到更一般的框架。

核心思想:Random Forest可以用来估计任何局部矩条件

通用框架

其中 是关于参数 的矩函数。

GRF的应用

任务矩条件估计量
回归
分位数回归
因果效应
工具变量
生存分析

Python实现:Quantile Regression Forest

python
from econml.grf import RegressionForest
import numpy as np
import matplotlib.pyplot as plt

# 生成异方差数据
np.random.seed(999)
n = 2000
X = np.random.uniform(0, 10, n).reshape(-1, 1)

# 条件均值和方差都依赖于X
mu = 2 * np.sin(X.ravel())
sigma = 0.5 + 0.3 * X.ravel()  # 异方差
Y = mu + sigma * np.random.randn(n)

# 标准回归森林(估计条件均值)
rf = RegressionForest(n_estimators=1000, random_state=42)
rf.fit(X, Y)

X_test = np.linspace(0, 10, 200).reshape(-1, 1)
Y_pred = rf.predict(X_test)

# 可视化
fig, ax = plt.subplots(figsize=(12, 6))

ax.scatter(X, Y, alpha=0.2, s=10, label='数据')
ax.plot(X_test, Y_pred, 'r-', linewidth=3, label='条件均值估计 E[Y|X]')
ax.plot(X_test, 2 * np.sin(X_test.ravel()), 'g--', linewidth=2, label='真实条件均值')

ax.set_xlabel('X', fontsize=12)
ax.set_ylabel('Y', fontsize=12)
ax.set_title('Generalized Random Forest: 回归', fontsize=14, fontweight='bold')
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

IV-Forest:工具变量的异质性效应

python
from econml.iv.dml import NonParamDMLIV
from sklearn.ensemble import RandomForestRegressor

# 模拟IV数据
np.random.seed(111)
n = 3000

# 协变量
X = np.random.uniform(0, 1, (n, 3))

# 工具变量
Z = np.random.binomial(1, 0.5, n)

# 内生处理变量(受未观测混杂影响)
unobserved_confounder = np.random.normal(0, 1, n)
T = 0.5 * Z + 0.3 * unobserved_confounder + np.random.normal(0, 0.2, n)

# 真实的异质性LATE
true_late = 3 + 5 * X[:, 0] - 2 * X[:, 1]

# 结果变量
Y = 10 + true_late * T + 2 * unobserved_confounder + np.random.normal(0, 0.5, n)

print("=" * 70)
print("IV Forest:工具变量的异质性效应")
print("=" * 70)

# NonParametric DML IV
iv_forest = NonParamDMLIV(
    model_y_xw=RandomForestRegressor(n_estimators=100),
    model_t_xw=RandomForestRegressor(n_estimators=100),
    model_t_xwz=RandomForestRegressor(n_estimators=100),
    discrete_treatment=False,
    discrete_instrument=False
)

iv_forest.fit(Y, T, Z=Z, X=X)

# 预测局部平均处理效应 (LATE)
late_pred = iv_forest.effect(X)

# 评估
r2_iv = r2_score(true_late, late_pred)
print(f"LATE预测R²: {r2_iv:.3f}")
print(f"估计的平均LATE: {late_pred.mean():.3f}")
print(f"真实的平均LATE: {true_late.mean():.3f}")

深度学习 + 因果推断

神经网络估计CATE

最新进展:用深度学习替代Random Forest

优势

  • 更好地捕捉非线性和交互效应
  • 可以处理图像、文本等非结构化数据
  • 端到端学习

方法

1. DragonNet (Shi et al., 2019)

架构

输入X → 共享层 → 分支:
                 ├─ 倾向得分分支 → e(X)
                 ├─ 结果Y(0)分支 → μ₀(X)
                 └─ 结果Y(1)分支 → μ₁(X)

CATE = μ₁(X) - μ₀(X)

损失函数

Python实现(简化版)

python
import torch
import torch.nn as nn
import torch.optim as optim

class DragonNet(nn.Module):
    """
    DragonNet for CATE estimation

    简化版实现,实际应用请使用causalml库
    """

    def __init__(self, input_dim, hidden_dim=100):
        super(DragonNet, self).__init__()

        # 共享表示层
        self.shared = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU()
        )

        # 倾向得分分支
        self.propensity = nn.Sequential(
            nn.Linear(hidden_dim, 1),
            nn.Sigmoid()
        )

        # Y(0)分支
        self.y0 = nn.Linear(hidden_dim, 1)

        # Y(1)分支
        self.y1 = nn.Linear(hidden_dim, 1)

    def forward(self, x):
        # 共享表示
        h = self.shared(x)

        # 预测
        propensity = self.propensity(h)
        y0 = self.y0(h)
        y1 = self.y1(h)

        return y0, y1, propensity

    def predict_cate(self, x):
        """预测CATE"""
        with torch.no_grad():
            y0, y1, _ = self.forward(x)
            return (y1 - y0).numpy()


# 训练DragonNet
def train_dragonnet(X, T, Y, epochs=100, lr=0.001):
    """训练DragonNet模型"""

    # 转换为Torch张量
    X_tensor = torch.FloatTensor(X)
    T_tensor = torch.FloatTensor(T).reshape(-1, 1)
    Y_tensor = torch.FloatTensor(Y).reshape(-1, 1)

    # 初始化模型
    model = DragonNet(input_dim=X.shape[1])
    optimizer = optim.Adam(model.parameters(), lr=lr)

    # 训练
    for epoch in range(epochs):
        optimizer.zero_grad()

        # 前向传播
        y0_pred, y1_pred, prop_pred = model(X_tensor)

        # 结果损失(只用观测到的结果)
        y_pred = T_tensor * y1_pred + (1 - T_tensor) * y0_pred
        loss_outcome = nn.MSELoss()(y_pred, Y_tensor)

        # 倾向得分损失
        loss_prop = nn.BCELoss()(prop_pred, T_tensor)

        # 总损失
        loss = loss_outcome + 0.1 * loss_prop

        # 反向传播
        loss.backward()
        optimizer.step()

        if (epoch + 1) % 20 == 0:
            print(f"Epoch {epoch+1}/{epochs}, Loss: {loss.item():.4f}")

    return model


# 使用之前的数据
X_torch = X[:, :3]  # 取前3个特征
model_dragon = train_dragonnet(X_torch, T, Y, epochs=100, lr=0.001)

# 预测CATE
tau_dragon = model_dragon.predict_cate(torch.FloatTensor(X_torch))

r2_dragon = r2_score(true_tau, tau_dragon.ravel())
print(f"\nDragonNet CATE预测R²: {r2_dragon:.3f}")

2. TARNet & CFRNet

TARNet(Treatment-Agnostic Representation Network):

  • 学习一个与处理无关的表示
  • 然后分别预测

CFRNet(Counterfactual Regression Network):

  • 在TARNet基础上加入分布匹配(通过MMD或Wasserstein距离)
  • 确保处理组和对照组的表示分布相似

Causal Forest的扩展

1. Multi-Armed Causal Forest

问题:多个处理选项(不仅是二元)

例子:教育干预有3种:

  • :无干预
  • :在线课程
  • :一对一辅导

目标:估计

Python实现

python
from econml.grf import MultiOutputGRF

# 模拟多处理数据
np.random.seed(222)
n = 2000
X_multi = np.random.uniform(0, 1, (n, 2))

# 3个处理选项
T_multi = np.random.choice([0, 1, 2], n)

# 异质性效应
tau1 = 5 + 10 * X_multi[:, 0]  # 在线课程效应
tau2 = 8 + 15 * X_multi[:, 1]  # 一对一辅导效应

# 结果
Y_multi = 50 + (T_multi == 1) * tau1 + (T_multi == 2) * tau2 + np.random.normal(0, 2, n)

print("=" * 70)
print("Multi-Armed Causal Forest")
print("=" * 70)
print(f"处理分布: {np.bincount(T_multi)}")

# 将多值处理转换为one-hot编码
from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder(sparse=False)
T_multi_encoded = encoder.fit_transform(T_multi.reshape(-1, 1))[:, 1:]  # 去掉第一列(基准组)

# 使用MultiOutputGRF(简化示例,实际需要更复杂的实现)
# 这里分别对每个处理组估计因果森林
from econml.grf import CausalForest

cf_treat1 = CausalForest(n_estimators=1000)
cf_treat2 = CausalForest(n_estimators=1000)

# 对处理1 vs 0
mask_01 = (T_multi == 0) | (T_multi == 1)
cf_treat1.fit(
    X_multi[mask_01],
    (T_multi[mask_01] == 1).astype(int).reshape(-1, 1),
    Y_multi[mask_01]
)

# 对处理2 vs 0
mask_02 = (T_multi == 0) | (T_multi == 2)
cf_treat2.fit(
    X_multi[mask_02],
    (T_multi[mask_02] == 2).astype(int).reshape(-1, 1),
    Y_multi[mask_02]
)

# 预测
tau1_pred = cf_treat1.predict(X_multi)
tau2_pred = cf_treat2.predict(X_multi)

print(f"\n处理1平均效应: {tau1_pred.mean():.2f} (真实: {tau1.mean():.2f})")
print(f"处理2平均效应: {tau2_pred.mean():.2f} (真实: {tau2.mean():.2f})")

# 最优处理分配
def optimal_treatment(tau1, tau2, cost1=0, cost2=0):
    """基于CATE选择最优处理"""
    benefits = np.column_stack([np.zeros(len(tau1)), tau1 - cost1, tau2 - cost2])
    return np.argmax(benefits, axis=1)

optimal_T = optimal_treatment(tau1_pred, tau2_pred)
print(f"\n最优处理分配: {np.bincount(optimal_T)}")

2. Survival Causal Forest

应用:估计处理对生存时间的异质性效应

例子:药物对不同患者的生存期提升

python
# 伪代码示例(需要专门的survival forest库)
from sksurv.ensemble import RandomSurvivalForest

# 生存数据
# event: 是否发生事件(0=截尾,1=死亡)
# time: 生存时间

# 对处理组和对照组分别建模
rsf_treat = RandomSurvivalForest(n_estimators=1000)
rsf_control = RandomSurvivalForest(n_estimators=1000)

# 预测生存函数
# S_treat(t|X) 和 S_control(t|X)

# CATE = median survival time difference

前沿研究方向

1. 因果发现 + CATE估计

问题:在不知道真实因果图的情况下估计CATE

方法

  • 结合因果发现算法(PC, GES, FCI)
  • 学习因果结构后再估计效应

2. 时间序列的因果推断

Synthetic Control + Causal Forest

  • 用CF估计不同单位在不同时间的处理效应
  • 结合合成控制方法

3. 网络数据的因果推断

问题:处理存在溢出效应(SUTVA违反)

Causal Forest for Networks

  • 考虑网络结构
  • 估计直接效应和间接效应

4. 因果强化学习

目标:学习最优动态处理策略

CATE在强化学习中的应用

  • 用CF估计状态-动作的异质性价值
  • 制定个性化策略

️ 实用建议

何时使用哪种方法?

场景推荐方法原因
RCT数据,样本充足标准Causal Forest简单有效
观察性数据,混杂严重DML + CF去偏差
高维特征(p > 100)DML正则化
需要推断和置信区间GRF渐近理论
非结构化数据(图像/文本)DragonNet深度学习
多个处理选项Multi-Armed CF自然扩展
生存分析Survival CF专门方法

模型选择和验证

python
from sklearn.model_selection import KFold
import numpy as np

def cv_cate_estimation(X, T, Y, methods, n_folds=5):
    """
    交叉验证比较不同CATE估计方法

    参数:
    - methods: 字典 {name: model}
    """
    kf = KFold(n_splits=n_folds, shuffle=True, random_state=42)

    results = {name: [] for name in methods.keys()}

    for train_idx, test_idx in kf.split(X):
        X_train, X_test = X[train_idx], X[test_idx]
        T_train, T_test = T[train_idx], T[test_idx]
        Y_train, Y_test = Y[train_idx], Y[test_idx]

        for name, model in methods.items():
            # 训练
            if hasattr(model, 'fit'):
                if 'DML' in name:
                    model.fit(Y_train, T_train, X=X_train)
                else:
                    model.fit(X_train, T_train.reshape(-1, 1), Y_train)

            # 预测
            if hasattr(model, 'effect'):
                tau_pred = model.effect(X_test)
            else:
                tau_pred = model.predict(X_test)

            # 评估(需要真实CATE,这里省略)
            # 实际应用中可以用代理指标如outcome预测准确度

            results[name].append(tau_pred.mean())

    return results

# 使用示例
methods = {
    'Standard CF': CausalForest(n_estimators=1000),
    'DML + CF': CausalForestDML(n_estimators=1000),
    'DML + GBM': CausalForestDML(
        model_y=GradientBoostingRegressor(),
        model_t=GradientBoostingRegressor(),
        n_estimators=1000
    )
}

# cv_results = cv_cate_estimation(X, T, Y, methods)

本节小结

核心要点

  1. Double ML

    • 解决正则化偏差
    • 样本分割 + Neyman正交化
    • 适合高维观察性数据
  2. Generalized Random Forests

    • 统一框架
    • 可估计多种局部参数
    • 理论保证强
  3. 深度学习 + 因果推断

    • DragonNet, TARNet, CFRNet
    • 适合非结构化数据
    • 需要大样本
  4. 扩展方法

    • Multi-Armed CF:多个处理选项
    • Survival CF:生存分析
    • Network CF:网络数据

前沿文献

  1. Chernozhukov et al. (2018). "Double/Debiased Machine Learning for Treatment and Structural Parameters." Econometrics Journal.

  2. Athey, Tibshirani, & Wager (2019). "Generalized Random Forests." Annals of Statistics.

  3. Shi et al. (2019). "Adapting Neural Networks for the Estimation of Treatment Effects." NeurIPS.

  4. Künzel et al. (2019). "Metalearners for Estimating Heterogeneous Treatment Effects using Machine Learning." PNAS.

  5. Nie & Wager (2021). "Quasi-Oracle Estimation of Heterogeneous Treatment Effects." Biometrika.


下一节预告

第6节:本章小结与练习中,我们将:

  • 总结本章核心概念
  • 提供综合练习题
  • 推荐进一步学习资源
  • 展望未来研究方向

探索前沿,推动因果推断的未来!

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