跳转至

因果推断机器学习


一句话说明

因果推断回答"X 是否真的导致 Y?"而不只是"X 和 Y 相关"——在生信中用于识别真正的致病基因(而非伴随表达的基因),评估干预效果(如某种治疗是否有效)。


核心知识点

相关 vs 因果

相关: A 和 B 同时升高(可能有共同原因 C)
因果: 改变 A 会导致 B 改变(do-演算,干预)

混杂因子:C 同时影响 A 和 B,让 A、B 看起来相关,但没有直接因果。

核心框架

Pearl 因果层次: 1. 关联(观察):P(Y|X) —— 看到 X 时,Y 是多少 2. 干预(do-演算):P(Y|do(X=x)) —— 强制设定 X,Y 会怎样 3. 反事实:如果当时做了不同的选择,Y 会怎样

常用方法

方法适用场景生信应用
随机对照试验 RCT最强因果证据药物临床试验
工具变量 IV有自然实验孟德尔随机化
双重差分 DiD前后对照研究政策评估
倾向性得分匹配 PSM观察性研究队列研究
因果森林异质处理效应精准医学
DoWhy/EconMLPython 框架通用因果分析

孟德尔随机化(MR)

利用遗传变异(SNP)作为工具变量,推断暴露因素对结局的因果效应: - 工具变量:SNP → 暴露 → 结局 - 假设:SNP 只通过暴露影响结局(不直接影响结局) - 应用:BMI 是否因果地导致 2 型糖尿病


实战代码

import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler

# ===== 1. 倾向性得分匹配(PSM)=====
# 场景:比较两组患者(治疗组 vs 对照组),消除混杂因子

np.random.seed(42)
n = 500  # 样本量

# 模拟观察数据:年龄、BMI、吸烟状态 → 影响是否接受治疗
age = np.random.normal(50, 10, n)           # 年龄
bmi = np.random.normal(25, 5, n)            # BMI
smoking = np.random.binomial(1, 0.3, n)    # 吸烟(0/1)

# 治疗概率受年龄和 BMI 影响(混杂!)
treatment_prob = 1 / (1 + np.exp(-(0.05*age + 0.1*bmi - 6 + 0.5*smoking)))
treatment = np.random.binomial(1, treatment_prob, n)  # 治疗分配(1=治疗,0=对照)

# 真实结局(治疗效果 = 0.3,另有年龄影响)
outcome = 0.3 * treatment + 0.02 * age + np.random.normal(0, 0.5, n)

df = pd.DataFrame({
    'age': age, 'bmi': bmi, 'smoking': smoking,
    'treatment': treatment, 'outcome': outcome
})

# 第1步:用逻辑回归估计倾向性得分
X_confounders = df[['age', 'bmi', 'smoking']]
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_confounders)

ps_model = LogisticRegression()
ps_model.fit(X_scaled, df['treatment'])
# 倾向性得分 = 每个样本接受治疗的预测概率
df['propensity_score'] = ps_model.predict_proba(X_scaled)[:, 1]

# 第2步:最近邻匹配(每个治疗样本找最相近倾向得分的对照样本)
treated = df[df['treatment'] == 1].copy()
control = df[df['treatment'] == 0].copy()

matched_pairs = []
used_control_idx = set()

for i, t_row in treated.iterrows():
    # 找倾向得分最接近的未被匹配的对照样本
    available_control = control[~control.index.isin(used_control_idx)]
    if len(available_control) == 0:
        break
    ps_diff = abs(available_control['propensity_score'] - t_row['propensity_score'])
    best_match_idx = ps_diff.idxmin()          # 最小差异的对照样本

    matched_pairs.append({
        'treated_outcome': t_row['outcome'],
        'control_outcome': available_control.loc[best_match_idx, 'outcome']
    })
    used_control_idx.add(best_match_idx)

matched_df = pd.DataFrame(matched_pairs)

# 第3步:计算匹配后的平均治疗效应(ATT)
att = (matched_df['treated_outcome'] - matched_df['control_outcome']).mean()
print(f'倾向得分匹配估计的平均治疗效应 ATT: {att:.3f}')
print(f'真实治疗效应: 0.300')

# ===== 2. 因果森林(异质处理效应)=====
# pip install econml
try:
    from econml.grf import CausalForest

    cf = CausalForest(
        n_estimators=100,     # 树的数量
        min_samples_leaf=10,  # 叶子节点最少样本
        random_state=42
    )
    X = df[['age', 'bmi', 'smoking']].values
    T = df['treatment'].values
    Y = df['outcome'].values

    cf.fit(X, T, Y)  # 拟合因果森林

    # 为每个个体估计处理效应(个性化治疗效应)
    te_pred = cf.effect(X)
    print(f'\n个体处理效应估计(前5个): {te_pred[:5].round(3)}')
    print(f'平均处理效应: {te_pred.mean():.3f}')
except ImportError:
    print("需要安装 econml: pip install econml")

# ===== 3. 孟德尔随机化(简化演示)=====
# 工具变量分析:SNP → 暴露(BMI)→ 结局(糖尿病风险)
def mendelian_randomization_wald(beta_exposure, beta_outcome, se_exposure, se_outcome):
    """
    Wald 估计量:最简单的 MR 方法
    单一 SNP 工具变量
    """
    # 因果效应估计 = SNP对结局的效应 / SNP对暴露的效应
    causal_estimate = beta_outcome / beta_exposure

    # Delta 法估计标准误
    se_ratio = abs(causal_estimate) * np.sqrt(
        (se_outcome/beta_outcome)**2 + (se_exposure/beta_exposure)**2
    )
    return causal_estimate, se_ratio

# 假设数据:某 SNP 与 BMI 的 GWAS 效应估计
beta_bmi_snp = 0.3       # SNP 对 BMI 的效应
se_bmi_snp = 0.05
beta_diabetes_snp = 0.12  # SNP 对糖尿病风险的效应
se_diabetes_snp = 0.03

causal_effect, se = mendelian_randomization_wald(
    beta_bmi_snp, beta_diabetes_snp, se_bmi_snp, se_diabetes_snp
)
print(f'\nMR Wald 估计:BMI → 糖尿病因果效应 = {causal_effect:.3f} ± {se:.3f}')
print(f'95% CI: [{causal_effect - 1.96*se:.3f}, {causal_effect + 1.96*se:.3f}]')

面试常问点

Q: 相关和因果的区别?举个生信例子。 A: 冰淇淋销量和溺水死亡相关(因为夏天),但冰淇淋不导致溺水(共同原因是夏天)。生信例子:某基因在肿瘤中高表达,但它可能是旁观者而非驱动因子,需要功能实验或 MR 证明因果。

Q: 孟德尔随机化的三大假设? A: ①相关性:SNP 与暴露强相关;②独立性:SNP 不受混杂因子影响;③排他性:SNP 只通过暴露影响结局(不存在水平多效性)。

Q: 工具变量的核心思路? A: 找一个"自然实验"——只影响暴露变量、不直接影响结局的外生变量,用它切断混杂路径。

Q: 因果森林和普通随机森林的区别? A: 普通随机森林预测 E[Y|X],因果森林估计异质处理效应 E[Y(1)-Y(0)|X],即不同亚组的因果效应。


速查表

术语解释
混杂因子同时影响原因和结果的第三变量
do-演算Pearl 的干预符号,P(Y|do(X))
ATE平均处理效应(全体人群)
ATT处理组的平均处理效应
PSM倾向性得分匹配
孟德尔随机化以遗传变异为工具变量的流行病学方法
工具变量 IV只影响暴露的外生变量
水平多效性SNP 同时影响多个性状(MR 假设违背)