统计学基础 | 因果推断之双网络深度因果模型

酥酥 发布于 2025-02-19 18 次阅读


 双网络深度因果模型(Doubly Robust Deep Causal Models, DR-DCM)是一种用于因果推断的机器学习方法,结合了倾向评分方法(Propensity Score Methods)结果回归方法(Outcome Regression Methods),以提高因果效应估计的稳健性和准确性。它的核心思想是双重稳健性(Doubly Robust, DR),即只要倾向评分模型结果回归模型其中之一是正确的,就能得到一致的因果效应估计。

1. 因果推断中的挑战

    因果推断的目标是估计处理(Treatment)结果(Outcome)的影响,特别是在观测数据(非随机试验)中,我们通常面临混杂偏倚(Confounding Bias)的问题。主流的因果推断方法通常有两大类:

  • 倾向评分方法(PSM, Propensity Score Methods):例如逆概率加权(IPW, Inverse Probability Weighting),使用倾向评分(treatment assignment probability)来调整不同组间的可比性。
  • 结果回归方法(Outcome Regression, OR):直接用回归模型估计治疗组和对照组的结果,然后计算它们的差值。

    但这两种方法各有局限,例如IPW依赖于倾向评分模型的准确性,而OR依赖于结果回归模型的正确性。如果模型错误,估计结果就会有偏差。因此,需要双重稳健(Doubly Robust, DR)的方法。

2. 双网络深度因果模型(DR-DCM)的核心思想

    DR-DCM结合倾向评分模型结果回归模型,并使用深度学习(Deep Learning)来增强建模能力,具体包括:

  • 倾向评分网络(Propensity Score Network, PSN):用于估计个体接受处理的概率 p(T=1∣X)。
  • 结果回归网络(Outcome Regression Network, ORN):用于分别预测处理组和对照组的结果Y^(T=1,X)和Y^(T=0,X)。
  • 双重稳健校正(Doubly Robust Adjustment):结合倾向评分加权(IPW)和结果回归模型,进行最终的因果效应估计。

数学表达

对于每个个体i,观测数据 (Xi,Ti,Yi):

  • Xi:个体特征
  • Ti:处理变量(1=接受处理,0=未接受处理)
  • Yi:观察到的结果

1. 估计倾向评分(Propensity Score):

e(X)=P(T=1∣X)

由倾向评分网络进行估计。

2. 估计结果回归(Outcome Regression):

Y^(1,X), Y^(0,X)

由结果回归网络进行估计。

3. 计算双重稳健估计量(Doubly Robust Estimator):

该估计量具有 双重稳健性,即即使e(X)或Y^(T,X)其中之一估计不准,因果效应τ^DR仍然是一致估计。

3. DR-DCM 的优势

  • 双重稳健性:即使一个模型(PSN或ORN)错误,仍然可以得到合理的因果效应估计。
  • 深度学习增强建模能力:深度神经网络能够自动学习复杂的非线性关系,提高倾向评分和结果回归的估计精度。
  • 适用于高维和非线性因果关系:传统因果推断方法在高维数据或复杂因果结构下可能表现不佳,而DR-DCM通过神经网络提升了估计能力。

示例:

    接下来我们生成一个示例数据集,然后使用PyTorch实现双网络深度因果模型

				
					import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import matplotlib.pyplot as plt
import seaborn as sns

# 1. 生成模拟数据
np.random.seed(42)
n = 5000  # 样本量
X = np.random.normal(0, 1, (n, 5))  # 5 个协变量
T = np.random.binomial(1, p=1 / (1 + np.exp(-X[:, 0] - X[:, 1])), size=n)  # 倾向评分与X0, X1相关
Y0 = X[:, 2] + np.random.normal(0, 1, n)  # 对照组
Y1 = X[:, 2] + X[:, 3] + np.random.normal(0, 1, n)  # 处理组
Y = T * Y1 + (1 - T) * Y0  # 观测结果

dev = torch.device("cuda" if torch.cuda.is_available() else "cpu")
X_tensor = torch.tensor(X, dtype=torch.float32).to(dev)
T_tensor = torch.tensor(T, dtype=torch.float32).to(dev)
Y_tensor = torch.tensor(Y, dtype=torch.float32).to(dev)
data_loader = DataLoader(TensorDataset(X_tensor, T_tensor, Y_tensor), batch_size=64, shuffle=True)

# 2. 定义神经网络(倾向评分网络和结果回归网络)
class NeuralNet(nn.Module):
    def __init__(self, input_dim):
        super(NeuralNet, self).__init__()
        self.model = nn.Sequential(
            nn.Linear(input_dim, 16),
            nn.ReLU(),
            nn.Linear(16, 8),
            nn.ReLU(),
            nn.Linear(8, 1)
        )

    def forward(self, x):
        return self.model(x)

# 倾向评分网络(PSN)
propensity_net = NeuralNet(input_dim=5).to(dev)
propensity_optimizer = optim.Adam(propensity_net.parameters(), lr=0.01)
criterion = nn.BCEWithLogitsLoss()

# 3. 训练倾向评分网络
for epoch in range(10):
    for batch_x, batch_t, _ in data_loader:
        propensity_optimizer.zero_grad()
        logits = propensity_net(batch_x).squeeze()
        loss = criterion(logits, batch_t)
        loss.backward()
        propensity_optimizer.step()

# 4. 训练结果回归网络
outcome_net = NeuralNet(input_dim=6).to(dev)  # 输入包括X和处理变量T
outcome_optimizer = optim.Adam(outcome_net.parameters(), lr=0.01)
criterion = nn.MSELoss()

for epoch in range(10):
    for batch_x, batch_t, batch_y in data_loader:
        outcome_optimizer.zero_grad()
        inputs = torch.cat([batch_x, batch_t.unsqueeze(1)], dim=1)  # 处理变量T拼接到输入特征中
        predictions = outcome_net(inputs).squeeze()
        loss = criterion(predictions, batch_y)
        loss.backward()
        outcome_optimizer.step()

# 5. 计算双重稳健估计
with torch.no_grad():
    e_x = torch.sigmoid(propensity_net(X_tensor)).squeeze()  # 倾向评分
    y1_pred = outcome_net(torch.cat([X_tensor, torch.ones(n, 1).to(dev)], dim=1)).squeeze()
    y0_pred = outcome_net(torch.cat([X_tensor, torch.zeros(n, 1).to(dev)], dim=1)).squeeze()

    doubly_robust = (T_tensor * (Y_tensor - y1_pred) / e_x + y1_pred) - \
                    ((1 - T_tensor) * (Y_tensor - y0_pred) / (1 - e_x) + y0_pred)

ate_dr = doubly_robust.mean().item()
print(f"Doubly Robust ATE Estimate: {ate_dr:.4f}")

				
			
代码解释
  1. 生成模拟数据

    • 自变量X,其中X0,X1影响倾向评分,X2,X3影响结果
    • 处理变量T服从一个逻辑回归概率模型。
    • 结果变量Y由T以及X生成。
  2. 构建神经网络

    • 倾向评分网络(PSN):估计P(T=1∣X)。
    • 结果回归网络(ORN):估计Y^(T=1,X)和Y^(T=0,X)。
  3. 训练倾向评分网络

    • 使用二元交叉熵损失(BCEWithLogitsLoss),训练用于分类。
  4. 训练结果回归网络

    • 目标是预测,使用均方误差损失(MSELoss)。
    • 训练时,输入数据 共同影响结果。
  5. 计算双重稳健估计量(Doubly Robust Estimator)

    • 计算倾向评分e(X)。
    • 预测两个处理组的结果Y^(1,X)和 Y^(0,X)。
    • 使用双重稳健公式计算平均处理效应(ATE)

    我们可以使用Matplotlib和Seaborn绘制图形来更直观地理解数据和模型的结果:

  1. 倾向评分分布图(Propensity Score Distribution):查看不同处理组的倾向评分分布,确保 PSN 学到了合理的分布。
  2. 处理组vs.对照组的结果分布(Outcome Distribution by Treatment):可视化处理组和对照组的结果Y分布情况。
  3. 双重稳健估计量分布(Doubly Robust Estimator Distribution):观察最终的因果效应估计值。
				
					
# 6. 数据可视化
plt.figure(figsize=(12, 4))
# 倾向评分分布
plt.subplot(1, 3, 1)
sns.histplot(e_x.cpu().numpy(), bins=30, kde=True, color='blue')
plt.title("Propensity Score Distribution")
plt.xlabel("Propensity Score")
plt.ylabel("Frequency")
# 处理组 vs 对照组的结果分布
plt.subplot(1, 3, 2)
sns.histplot(Y[T == 1], bins=30, kde=True, color='red', label="Treated", alpha=0.6)
sns.histplot(Y[T == 0], bins=30, kde=True, color='green', label="Control", alpha=0.6)
plt.title("Outcome Distribution by Treatment")
plt.xlabel("Outcome")
plt.ylabel("Frequency")
plt.legend()
# 双重稳健估计分布
plt.subplot(1, 3, 3)
sns.histplot(doubly_robust.cpu().numpy(), bins=30, kde=True, color='purple')
plt.title("Doubly Robust Estimator Distribution")
plt.xlabel("Estimated Effect")
plt.ylabel("Frequency")
plt.tight_layout()
plt.show()
				
			

— 文章来源 策源数据