Frontier / Causal Discovery
因果发现:用 AI 从数据中学习因果图(PC、LiNGAM、NOTEARS)及其边界
当你不确定变量之间谁影响谁,因果发现算法尝试从观测数据反推 DAG。它擅长生成假设,但识别假设很强,社科应用必须谨慎。
原理图解
一图看懂原理
先看这里
学完这一页你应该会什么
知道因果发现的目标:从数据估计 DAG / CPDAG,而不是估单个效应。
理解三类方法:约束法(PC)、函数因果模型(LiNGAM)、连续优化(NOTEARS)。
知道关键假设:因果充分性(无未观测共因)、忠实性、(LiNGAM)非高斯噪声。
理解观测数据通常只能识别到马尔可夫等价类(CPDAG),部分边方向不可辨。
把因果发现当"假设生成器",再用设计 / 实验 / 专家知识检验。
学习路径
学习路径:从相关结构到候选因果图
按这条路径学习:先估骨架,再尽量定向,认清等价类边界,最后把图当假设交给研究设计检验。
Step 1
Data
观测多变量数据,目标是结构而非单个效应。
X_1..X_p
Step 2
Skeleton
用条件独立检验删去间接 / 虚假边。
X_i⟂X_j|S
Step 3
Orient
用 v-结构、非高斯或时间顺序定向。
v-structure
Step 4
Equivalence
认清观测常只识别到 CPDAG。
CPDAG
Step 5
Validate
把图当假设,用设计 / 实验检验关键边。
design test
01 / 直觉
核心直觉
因果发现回答的是"图长什么样",而不是"某条边有多大"。它从相关结构加上假设反推方向。
约束法(PC)用条件独立检验删边、再定向;但仅凭观测,常只能定到马尔可夫等价类(CPDAG)——有些边方向无法辨认。
要恢复唯一方向,需要额外结构假设:LiNGAM 利用线性 + 非高斯噪声的不对称性定向;NOTEARS 用一个可微的"无环约束"把组合搜索变成连续优化。
02 / 数学
从联合分布到一张可检验的因果图
01 / 图与分解
因果图是 DAG,联合分布按父节点分解。因果发现就是从数据估计这张图的结构。
P(X_1,...,X_p) = prod_j P(X_j | pa(X_j))02 / 约束法(PC)与等价类
用条件独立检验:若 X_i 与 X_j 在某条件集 S 下独立则删去边;再用 v-结构(对撞)定向。仅凭观测通常只能识别到 CPDAG。
X_i ⟂ X_j | S => remove edge i–j03 / 忠实性与因果充分性
PC 依赖三件事:忠实性(数据中的独立性恰由图蕴含)、因果充分性(无未观测共因)、独立性检验正确。任一不满足,结果都可能错。
faithfulness + causal sufficiency + valid CI tests04 / LiNGAM:用非高斯定向
线性非高斯无环模型 X=BX+e,其中 e 各分量非高斯且独立。非高斯性打破对称,使因果次序与系数矩阵 B 可唯一识别(ICA 类方法)。
X = B X + e, e 非高斯且相互独立05 / NOTEARS:连续优化
把"无环"写成一个光滑约束 h(W)=0,用连续优化代替对 DAG 空间的组合搜索,使结构学习可被梯度方法求解。
min_W loss(W) s.t. h(W)=tr(exp(W∘W))−p=003 / 代码
代码案例:条件独立、等价类与非高斯定向
下面用小模拟展示:条件独立如何删掉一条"看似存在"的边、为什么高斯观测下方向不可辨、以及非高斯如何帮助定向。
案例 1:条件独立删掉间接边
链式 X→Y→Z 中,X 与 Z 相关,但在给定 Y 后独立,于是没有直接 X–Z 边。
import numpy as np
rng = np.random.default_rng(0)
n = 4000
X = rng.normal(size=n)
Y = 1.2 * X + rng.normal(size=n)
Z = 0.9 * Y + rng.normal(size=n)
def pcorr(x, y, z):
rx = x - np.polyval(np.polyfit(z, x, 1), z)
ry = y - np.polyval(np.polyfit(z, y, 1), z)
return np.corrcoef(rx, ry)[0, 1]
print("corr(X,Z) =", round(np.corrcoef(X, Z)[0,1], 3))
print("pcorr(X,Z | Y) =", round(pcorr(X, Z, Y), 3))预期输出
corr(X,Z) = 0.73
pcorr(X,Z | Y) = 0.00怎么读这段代码
- X 与 Z 边际相关,看似有直接关系。
- 给定中介 Y 后条件独立,说明没有直接边。
- PC 正是用这种条件独立删边、还原骨架。
案例 2:高斯观测下方向不可辨(等价类)
X→Y 和 X←Y 给出相同的相关结构,仅凭高斯观测无法区分方向。
import numpy as np
rng = np.random.default_rng(1)
n = 5000
X = rng.normal(size=n); Y = 0.8 * X + rng.normal(size=n) # X -> Y
# Fit both directions; both explain the data symmetrically.
b_xy = np.polyfit(X, Y, 1)[0]
b_yx = np.polyfit(Y, X, 1)[0]
print("slope Y~X =", round(b_xy, 3), " slope X~Y =", round(b_yx, 3))
print("corr identical both ways:", round(np.corrcoef(X, Y)[0,1], 3))预期输出
slope Y~X = 0.80 slope X~Y = 0.49
corr identical both ways: 0.62怎么读这段代码
- 两个方向都能拟合数据,相关结构对称。
- 所以高斯观测只能识别到马尔可夫等价类。
- 要定向,需要实验、时间顺序或非高斯等额外信息。
案例 3:非高斯打破对称,帮助定向
LiNGAM 思路:正确方向上残差与原因独立,反方向则不独立。
import numpy as np
from scipy import stats
rng = np.random.default_rng(2)
n = 5000
X = rng.laplace(size=n) # non-Gaussian cause
Y = 0.9 * X + rng.laplace(size=n) # X -> Y
res_fwd = Y - np.polyval(np.polyfit(X, Y, 1), X) # regress Y on X
res_bwd = X - np.polyval(np.polyfit(Y, X, 1), Y) # regress X on Y
# Lower dependence (corr with regressor) indicates the causal direction.
print("forward |corr(res, X)| =", round(abs(np.corrcoef(res_fwd, X)[0,1]), 3))
print("backward|corr(res, Y)| =", round(abs(np.corrcoef(res_bwd, Y)[0,1]), 3))预期输出
forward |corr(res, X)| = 0.00
backward|corr(res, Y)| = 0.21怎么读这段代码
- 正确方向 X→Y 上,残差与 X 独立(相关≈0)。
- 反方向残差与 Y 仍相关,暴露错误方向。
- 这正是 LiNGAM 用非高斯不对称定向的直觉。
04 / 案例
案例:在发展指标间发现候选因果图再做检验
- 研究问题:教育、健康、收入、基础设施等指标之间的因果结构未知,想先获得可检验的假设。
- 用 PC 还原骨架与可定向部分,得到一个 CPDAG;用 LiNGAM 或时间顺序尝试进一步定向。
- 把发现的图当"假设",再用准实验 / 工具变量 / 制度知识检验关键边,而不是直接当成因果结论。
- 可信报告需说明:所用假设(充分性、忠实性)、对未观测共因的敏感性、等价类中无法定向的边,以及后续如何用设计验证。
05 / 因果
接入因果估计:发现图 → 调整集 → 设计
因果发现不直接给效应,而是给一张候选图;这张图最有用的产物是"该控制什么"(后门调整集),再交给你已会的估计方法。
01 / 发现 → 后门调整集
用候选 DAG 读出满足后门准则的调整集,避免控制对撞或中介。
adjust by Z s.t. back-door(Z) holds02 / 调整集 → DML / 匹配
把调整集作为控制 X 放进 DML / AIPW / 匹配估处理效应。
03 / 不可定向边 → 用设计补
等价类里无法定向的关键边,用准实验 / IV / 时间顺序补充识别。
04 / 发现是探索,不是确认
同一批数据上"发现 + 估计"会过度乐观;探索与确认应分开(样本分裂 / 预注册)。
三条红线:(1) 因果充分性几乎不可验证,未观测共因会让发现的边失真;(2) 观测数据常只到等价类,别把 CPDAG 当唯一 DAG;(3) 发现与确认要分开,避免在同一数据上自我验证。
06 / 风险
常见误区
参考资料
- Spirtes, Glymour, and Scheines (2000), Causation, Prediction, and Search, MIT Presshttps://mitpress.mit.edu/9780262527927/causation-prediction-and-search/
- Shimizu et al. (2006), A Linear Non-Gaussian Acyclic Model for Causal Discovery (LiNGAM), JMLRhttps://www.jmlr.org/papers/v7/shimizu06a.html
- Zheng et al. (2018), DAGs with NO TEARS: Continuous Optimization for Structure Learning, NeurIPShttps://arxiv.org/abs/1803.01422
- Peters, Janzing, and Schölkopf (2017), Elements of Causal Inference, MIT Presshttps://mitpress.mit.edu/9780262037310/elements-of-causal-inference/