想象一位老侦探接手一桩悬案。现场有六个关键人物,证词和物证东一块西一块;侦探最想知道的是“谁的出现导致了谁的行动”。普通分析能告诉他“张三出现时李四大概率也在”,但这只是相关,不是因果。侦探必须回答的是:如果我阻止张三出现,李四还会行动吗?这才是因果。可问题在于,真正可能的“因果剧本”有成百上千万种。GES,全称“Greedy Equivalence Search——贪婪等价搜索”,就是这位侦探的破案方法论:它把一堆无法区分的剧本归为一个文件夹,先大胆地在文件夹之间连线,再冷静地删掉经不起推敲的线,最终锁定一个最简洁、最能解释所有证据的因果版本。这套方法不仅在理论上保证“证据越来越多、结论越来越准”,在实践里也成了人工智能理解因果、安全对齐的重要工具。

岗位关联

GES 是因果发现领域“基于分数方法”的标杆算法。掌握它,你就掌握了从数据中恢复因果关系的高级技能——这是可解释 AI、安全对齐等前沿方向的必备武器。

目录
  1. 可视化演示
  2. 问题定位:侦探为何换思路
  3. 等价类空间:侦探的合并同类项
  4. GES两阶段:先大胆连线,后冷静删线
  5. BIC评分:侦探的真相计分器
  6. 理论优势:侦探的破案为何有保证
  7. 实践应用:让AI侦探上岗
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示GES贪婪等价搜索的两阶段操作流程(FES增边+BES删边)、马尔可夫等价类概念、以及BIC/BDeu等评分函数对比,交互切换三种模式探索因果发现算法。

本节配有交互动效(进入视口后自动加载,约 3KB)。

'+CAPS.mode1+'

问题定位:侦探为何换思路

侦探破案的第一步是确定侦查口径。普通的统计员看到“张总一出事,李副总就离职”,会记录一条“高相关”;但侦探必须回答一个更硬的问题:是张总的事直接逼走了李副总,还是背后有个董事会决议同时导致了两件事?统计上的相关性只是一种“同现关系”,因果则是“如果干预前者,后者会变”的传导机制。因果发现的任务,正是从观测数据里反推这种传导链条。

半个多世纪的因果研究发现,这条路要走得通,得先定一个“好图”的标准。基于分数的方法就这样登场:先把候选因果图变成数学对象,再定义一个“分数函数”告诉算法——这张图解释数据的能力有多强、结构有多简洁;随后在图的海洋里搜索分数最高的图。侦探的办法变成了一场寻优:在千万个版本里,按计分本挑最高分。

天真地在所有DAG上做穷举是不可行的。p个变量的DAG数量约等于2的p(p-1)/2次方:p=10时就有约3.5×10^25种。搜索空间如此爆炸,侦探不可能挨个翻剧本。GES的高明之处,是只在这片“剧本海”的压缩版——马尔可夫等价类空间——上行走,并且用两阶段贪婪落子:先增边后删边。用一句话总结:不在十万个剧本里逐本看,而把相同结局的剧本装进一个文件夹,在文件夹之间跳着找。

所以侦探换思路了:不打遍所有剧本,只带着一本计分册和一套“合并同类项”的文件夹,在压缩后的因果空间里走直线。这就是GES与朴素穷举的最大分水岭。

∣Dp∣≤2(p2)=2p(p−1)/2|\mathcal{D}_p| \le 2^{\binom{p}{2}} = 2^{p(p-1)/2}
  1. DAG集合大小$\mathcal{D}_p$ 表示 $p$ 个节点上所有可能的DAG集合,“竖线加≤”表示它的规模最多不超过右边这个数。
    ∣Dp∣≤2(p2)|\mathcal{D}_p| \le 2^{\binom{p}{2}}
  2. 节点对数$\binom{p}{2}=\frac{p(p-1)}{2}$ 统计 $p$ 个节点里有多少个节点对,这是指数上标的来源。
    (p2)=p(p−1)2\binom{p}{2}=\frac{p(p-1)}{2}
  3. 二分状态$2^{\binom{p}{2}}$ 表示每个节点对都有“有边”/“无边”两种可能,所有可能并行相乘。
    2(p2)2^{\binom{p}{2}}
  4. 现实差距真实DAG还要排除成环方向,只会更少,但仍是指数级——这就是为什么必须聪明地搜索。
    2p(p−1)/22^{p(p-1)/2}

等价类空间:侦探的合并同类项

侦探在翻阅证词时常常遇到这样的尴尬:两张剧情图都能解释所有口供,谁先到、谁引荐、谁下手——细节方向不同,但证词统统“兼容”。它们就是一对“等价剧本”。聪明的做法不是揪住其中一个反复推演,而是把它们收进同一个文件夹,标上“暂不可区分”。马尔可夫等价类,就是因果世界的这个文件夹。

两个DAG什么时候能放进同一个文件夹?它们的骨架(谁跟谁有边)和V结构(谁指向谁且中间不相邻地汇聚)必须完全一致。骨架是“人际网络图”,V结构是“被共同证人看见的紧张关系”。二者一致,则两张图对任何数据都给出相同的条件独立声明——统计学上无法区分,因此可以在尺度上视为一个整体。

在数学上,GES用一个CPDAG(完全部分有向无环图)来代表整个等价类:能确定方向的边用箭头,不能确定的边画成无向直线。这样,搜一个等价类相当于搜一个节点,搜索的“步长”就被拉大了。Chickering的GES正是在这种压缩图上做合法插入与合法删除操作——每一步改动的不是一张DAG,而是一整类“兼容剧本”。

侦探有了“合并同类项”的文件夹,接下来的贪婪遍历就有了抓手:每一次移动,整个文件夹一起搬家。等价类空间就是侦探案件板上的压缩地图。

G1∼G2  ⟺  Sk(G1)=Sk(G2)∧V(G1)=V(G2)G_1 \sim G_2 \iff \text{Sk}(G_1)=\text{Sk}(G_2) \wedge \mathcal{V}(G_1)=\mathcal{V}(G_2)
  1. 等价符号$G_1 \sim G_2$ 读作“两个DAG马尔可夫等价”,即它们编码相同的条件独立信息。
    G1∼G2G_1 \sim G_2
  2. 冲要条件$\iff$ 表示左侧成立当且仅当右侧两个条件同时成立,缺一不可。
      ⟺  \iff
  3. 骨架相同$\text{Sk}(G_1)=\text{Sk}(G_2)$ 要求两个图去掉方向后的无向边集合一致。
    Sk(G1)=Sk(G2)\text{Sk}(G_1)=\text{Sk}(G_2)
  4. V结构相同$\mathcal{V}(G_1)=\mathcal{V}(G_2)$ 要求所有碰撞结构一致——这些是无法伪装的方向锚点。
    V(G1)=V(G2)\mathcal{V}(G_1)=\mathcal{V}(G_2)

GES两阶段:先大胆连线,后冷静删线

案件信息上墙之后,侦探第一轮操作是“大胆假设”:把所有有蛛丝马迹的关系都连上线——A可能见过B,B可能给C递过话,C似乎能影响D……一路加线,直到再加任何一条,计分本反而掉分。第二轮是“小心求证”:从更密的图开始,一条条删掉那些“删了也没影响”的线索线——删到不能再多删一条,否则分数下降为止。

GES的前向阶段就是第一轮:从空图(空CPDAG)出发,反复执行能让BIC分数提升最大的合法加边操作,直到分数不再上升;后向阶段则是第二轮:反复执行能让BIC分数提升最大的合法删边操作,直到无法继续提升。两个阶段都是典型的贪婪策略——每一步都吃眼前最大的一块“分数提升”。

关键在于,这里的每一条边操作都发生在等价类(CPDAG)上,而非某个具体DAG上;合法插入/合法删除算子保证新图仍然是合法的等价类。于是复杂度从“逐图搜索”变成“逐类搜索”。前向阶段贡献了主要的边骨架,后向阶段再去掉残余的噪声边——两者配合,才形成GES名字里的“增删”两拍。

侦探两轮下来,案件板终于安静了:没有任何一条线还能在不动摇证据基础的前提下被改动。这一“静默点”,就是GES的终点——一个让证据最舒服、结构最克制的因果版本。

op∗=arg⁡max⁡op∈O[BIC(op(G))−BIC(G)]op^* = \arg\max_{op \in \mathcal{O}} \left[\text{BIC}(op(G)) - \text{BIC}(G)\right]
  1. 操作空间$\mathcal{O}$ 是当前状态下所有合法插入/删除操作的集合。
    O\mathcal{O}
  2. 当前的图$G$ 是当前的CPDAG(等价类代表)。
    GG
  3. 分数差$\text{BIC}(op(G))-\text{BIC}(G)$ 计算执行操作前后BIC的变化量。
    BIC(op(G))−BIC(G)\text{BIC}(op(G))-\text{BIC}(G)
  4. 贪婪规则$\arg\max$ 从所有操作里选出“增量最大”的操作 $op^*$,然后执行它并重复。
    op∗=arg⁡max⁡op∈OΔBICop^* = \arg\max_{op \in \mathcal{O}} \Delta\text{BIC}

BIC评分:侦探的真相计分器

剧本多了难免各说各话,侦探需要一个统一的计分标准:“解释力”加分,“私设剧情”扣分。一个剧本若能不打补丁、不盲猜就贴合所有证词,分数就高;反之,若为了自圆其说不断添加路人甲、乙、丙,分数就低。这位侦探手里的计分本,正是BIC。

BIC的全称是贝叶斯信息准则。它把“图解释数据的能力”和“图的过度复杂罚金”放进同一个式子:解释得越多越好,但每多一个参数都要交一笔“复杂度税”。这个权衡让GES既能抓住真实信号,又不至于把噪声也当成因果关系。

对给定的候选图G和数据D,BIC的计算分为两项。第一项是对数似然:在最优参数估计下,数据被这张图解释得有多好;第二项是复杂度惩罚:图的自由参数个数乘以log样本量的一半。样本量越大,惩罚越重——这符合侦探直觉:证据越充分,越不能靠“加设定”蒙混过关。

侦探的计分本一旦定下来,整场搜索就不再是拍脑袋。无论是第一轮的加线还是第二轮的删线,每一步都只是“朝分数更高的方向走一格”——BIC就是驱动整台破案机器的引擎。

BIC(G)=log⁡P(D∣G,θ^)−d(G)2log⁡m\text{BIC}(G) = \log P(D \mid G, \hat{\theta}) - \frac{d(G)}{2} \log m
  1. 对数似然项$\log P(D \mid G, \hat{\theta})$ 是在最优参数 $\hat{\theta}$ 下数据 $D$ 的似然对数,数值越大说明图解释得越好。
    log⁡P(D∣G,θ^)\log P(D \mid G, \hat{\theta})
  2. 复杂度指标$d(G)$ 是图 $G$ 的自由参数个数,边越多参数越多。
    d(G)d(G)
  3. 样本惩罚$\frac{d(G)}{2}\log m$ 随样本量 $m$ 增大而变大,惩罚复杂模型。
    d(G)2log⁡m\frac{d(G)}{2}\log m
  4. 整体方向BIC的数值越高(越接近0)代表模型越优,GES的每一步都在朝更高的BIC移动。
    BIC(G)=log⁡P(D∣G,θ^)−d(G)2log⁡m\text{BIC}(G) = \log P(D \mid G, \hat{\theta}) - \frac{d(G)}{2} \log m

理论优势:侦探的破案为何有保证

侦探的老搭档总问他:你这么贪心,会不会被眼前利益带偏?GES有底气回答:只要证据足够多,我的结论一定收敛到真相。这就像目击证词从10份变成10000份后,那些靠巧合形成的“假联系”自然崩解,剩下的因果剧本再难被伪造。

这一底气来自大样本一致性定理。Chickering在2002年证明:在标准正则条件下(数据忠实于某个真实DAG,BIC作为评分),随着样本量趋于无穷,GES返回的估计等价类以概率1等于真实数据生成机制的等价类。换句话说,数据量管够,贪婪也是可靠侦探。

为什么等价类空间搜索比单DAG搜索优越?一方面,单DAG空间里许多相邻图其实代表同一个等价类,搜索会绕远路;等价类空间把“同义反复”压缩掉,搜索步数更少。另一方面,BIC与数据规模联动,样本越大对复杂图惩罚越严,最终留下的骨架越接近真实结构。当然也要诚实:有限样本下,贪婪策略可能停在局部最优——这也是后续研究用“带重启的GES”或增强版方法改进的动机。

侦探把这套流程写进手册:先合并同类项,再贪心两阶段,最后用BIC把关——理论保证让这套“破案术”升格为“破案科学”,这也是GES至今地位稳固的原因。

lim⁡n→∞Pr⁡(E^n=E(G∗))=1\lim_{n\to\infty} \Pr\left(\hat{\mathcal{E}}_n = \mathcal{E}(G^*)\right) = 1
  1. 极限符号$\lim_{n\to\infty}$ 表示样本量 $n$ 趋于无穷时观察结论。
    lim⁡n→∞\lim_{n\to\infty}
  2. 估计输出$\hat{\mathcal{E}}_n$ 是样本量为 $n$ 时GES输出的估计等价类。
    E^n\hat{\mathcal{E}}_n
  3. 真实目标$\mathcal{E}(G^*)$ 是真实数据生成DAG $G^*$ 所在的等价类。
    E(G∗)\mathcal{E}(G^*)
  4. 概率为1$\Pr(\cdot)=1$ 说明收敛几乎是必然的,不依赖运气。
    Pr⁡(E^n=E(G∗))=1\Pr\left(\hat{\mathcal{E}}_n = \mathcal{E}(G^*)\right) = 1

实践应用:让AI侦探上岗

手册再漂亮,也要有人用。如今,这位侦探被请进了AI公司:大模型动不动就“一本正经地胡说八道”,系统行为因果不明,追责就像在雾里找人。GES从数据里画出的因果图,正好给AI安上一双“找因果的眼睛”。

在可解释AI方向,GES能从行为日志和特征数据中恢复出关键变量的因果结构,让模型决策不再只是黑箱推理:哪个输入驱动了哪个输出,一目了然。在安全对齐方向,因果图可以帮助识别“有毒链路”——比如某类提示词会经由中间变量触发有害回答;一旦定位,就能针对性拦截或打断因果传播。

工程上,GES已经沉淀成可直接调用的工具:R语言的pcalg包、Python的gCastle和bnlearn等都提供GES或改进版实现。评估算法恢复质量时,常用结构汉明距离SHD来度量“预测图和真实图相差几条边”——边差越少,说明侦探还原得越准。实际项目中,GES常与专家知识、干预实验结合:先靠观察数据得到候选因果结构,再设计实验验证关键连接。

侦探手册最终变成工程脚手架:从可解释AI的因果报表,到安全对齐的链路拦截,再到开源库里的几行调用——GES把“找因果”这件事,从理论变成了代码。

SHD(G,G^)=∣E(G)△E(G^)∣\text{SHD}(G,\hat{G}) = |E(G) \triangle E(\hat{G})|
  1. 两图边集$E(G)$ 与 $E(\hat{G})$ 分别表示真实图和估计图的边集合。
    E(G),E(G^)E(G), \quad E(\hat{G})
  2. 对称差$A \triangle B$ 表示“只在其中一个集合里的元素”构成的集合。
    E(G)△E(G^)E(G) \triangle E(\hat{G})
  3. 求模累计$|\cdot|$ 统计这些不匹配边的总数——这就是还原质量的一种直观度量。
    ∣E(G)△E(G^)∣|E(G) \triangle E(\hat{G})|
  4. 应用读法SHD越小说明估计越准;在实验中常对比GES与朴素贪心搜索的结果。
    SHD(G,G^)\text{SHD}(G,\hat{G})

AI 应用场景

医疗观察性研究:从电子病历里挖出危险因素链

阶段:因果结构学习(数据分析与假设生成)

解决的问题:传统回归只能控制已知混杂变量,面对电子病历中几十个变量构成的复杂网络,很容易漏掉未知因果路径;AI从业者需要一张解释“哪些指标导致哪些结局”的结构图来指导后续实验。

具体案例:某医院数据分析团队用GES对脓毒症患者生命体征与用药记录做因果发现:前向阶段先连出血压-心率-用药的候选边,后向阶段删掉虚警边,最终得到“炎症指标→血压下降→用药调整→转归”的等价类因果链,据此设计前瞻性验证队列。

大模型安全对齐:因果审计阻断有害链路

阶段:模型可解释性评估与安全对齐

解决的问题:大模型幻觉和偏见往往来自训练语料里的虚假相关,人工审计难以定位;AI安全团队需要用因果结构识别“触发词→中间表示→有害输出”的传递路径。

具体案例:某对齐团队将模型在不同提示下的内部注意力特征与输出得分记录成表,用GES学出因果图,发现“身份词→情绪唤醒→越狱回答”链路;随后在中间变量处加入干预模块,成功把有害输出率降低约40%。

推荐系统反事实评估:补贴该给谁

阶段:策略优化与因果效果估计

解决的问题:观察数据只能看到“推荐了→点了”,无法回答反事实问题“如果不推荐,他还会买吗?”GES先重建用户兴趣因果图,再做反事实推断,避免把关联当因果。

具体案例:某电商平台用GES从用户浏览、收藏、下单记录中学出“优惠券敏感度”的因果结构,发现“历史比价行为→优惠券打开率→最终转化”链路,据此调整补贴发放策略,在预算不变情况下转化率提升12%。

Python 演示

python100 行
import numpy as np def bic_local(data, parents, child):    # 计算子节点 child 在给定父节点集合下的局部BIC贡献    X = data[:, parents]    y = data[:, child]    n = len(y)    if X.size == 0:        mu = np.mean(y)        sigma2 = np.mean((y - mu) ** 2)        loglik = -0.5 * np.sum((y - mu) ** 2 / (sigma2 + 1e-9)                               + np.log(2 * np.pi * sigma2 + 1e-9))        n_params = 2    else:        X_aug = np.column_stack([np.ones(n), X])        beta = np.linalg.lstsq(X_aug, y, rcond=None)[0]        resid = y - X_aug @ beta        sigma2 = np.mean(resid ** 2)        loglik = -0.5 * np.sum(resid ** 2 / (sigma2 + 1e-9)                               + np.log(2 * np.pi * sigma2 + 1e-9))        n_params = X_aug.shape[1] + 1    return loglik - 0.5 * n_params * np.log(n) def has_cycle(graph):    # 拓扑排序判断当前有向图是否含环    indeg = [0] * len(graph)    for child in graph:        for p in graph[child]:            indeg[child] += 1    q = [i for i in range(len(graph)) if indeg[i] == 0]    cnt = 0    while q:        u = q.pop()        cnt += 1        for child in range(len(graph)):            if u in graph[child]:                indeg[child] -= 1                if indeg[child] == 0:                    q.append(child)    return cnt != len(graph) def greedy_ges(data, max_parents=3):    # 简化版GES: 前向增边 + 后向删边, 使用BIC增量贪心    d = data.shape[1]    graph = {i: [] for i in range(d)}    # 前向增边    while True:        best_delta = 0.0        best_edge = None        for child in range(d):            for p in range(d):                if p == child or p in graph[child]:                    continue                if len(graph[child]) >= max_parents:                    continue                new_parents = graph[child] + [p]                delta = bic_local(data, new_parents, child) - bic_local(data, graph[child], child)                tmp = {k: list(v) for k, v in graph.items()}                tmp[child].append(p)                if has_cycle(tmp):                    continue                if delta > best_delta:                    best_delta = delta                    best_edge = (p, child)        if best_edge is None:            break        p, child = best_edge        graph[child].append(p)    # 后向删边    while True:        best_delta = 0.0        best_edge = None        for child in range(d):            for p in graph[child]:                new_parents = [x for x in graph[child] if x != p]                delta = bic_local(data, new_parents, child) - bic_local(data, graph[child], child)                if delta > best_delta:                    best_delta = delta                    best_edge = (p, child)        if best_edge is None:            break        p, child = best_edge        graph[child].remove(p)    return graph if __name__ == "__main__":    np.random.seed(42)    n = 300    x1 = np.random.randn(n)    x2 = 0.6 * x1 + np.random.randn(n)    x3 = 0.5 * x2 + np.random.randn(n)    data = np.column_stack([x1, x2, x3])    dag = greedy_ges(data, max_parents=2)    print("学到的父节点关系:")    for var in range(3):        parents = dag[var]        if parents:            print("X%d <- %s" % (var + 1, " ".join("X%d" % (p + 1) for p in parents)))        else:            print("X%d <- 无父节点" % (var + 1))
目的:用 NumPy 实现一个简化版 GES——前向增边、后向删边,在每步用局部 BIC 增量做贪婪决策,从人工生成的线性高斯数据中恢复因果结构。
  1. return loglik - 0.5 * n_params * np.log(n)BIC核心:拟合度减去复杂度惩罚,这就是计分器的读数
  2. delta = bic_local(data, new_parents, child) - bic_local(data, graph[child], child)用增量贪心判断“这一步值不值得走”
  3. if has_cycle(tmp): continue前向阶段严禁加出环,因果图必须保持DAG
  4. if delta > best_delta:贪婪地记住当前最能提升分数的那条边
  5. graph[child].append(p)前向阶段真正落子,把父节点挂到子节点名下
  6. graph[child].remove(p)后向阶段擦除冗余连线,完成“删线”动作

常见误区

误区GES名字里有个“贪”,所以我以为它会把所有图都试一遍,保证找到全局最优的那张DAG,输出时也是一张带箭头的完整图。

正解GES并不遍历所有DAG。它在马尔可夫等价类(CPDAG)上做贪心搜索:每步只选当前分数增量最大的操作。大样本条件下它一致收敛到真实等价类,但有限样本下完全可能停在局部最优。输出通常是一个CPDAG,里面有些边方向是不确定的——这恰恰是数据要说的话,而不是算法的失败。

为何常见:很多教程把因果发现写成“找到最优图”,初学者自然以为GES是暴力搜索加全局冠军;贪婪的“局部最优”暗示也很容易让人误读成“全局最优”。

误区我以为前向增边就是先不管三七二十一,把所有可能的边全画上去,再在后向阶段慢慢删——所以前向阶段结束时图一定非常密。

正解前向阶段每一步依旧是贪婪的:只加当前BIC增量最大的那一条边,加完后重新评估,直到任何合法加边都不能提升BIC才停。因此前向阶段结束时,图是“在增边意义下已经局部最优”的状态,而非全连接。

为何常见:把“增边/删边”理解成一次性批量操作很自然;但GES的每一步都是重新搜索状态空间,而不是简单按顺序画完。

误区我看到某个边让BIC增加了100,就觉得这条边的因果效应一定非常强,可以写进结论说X导致Y。

正解BIC衡量的是“图解释数据的质量”,不是“这条边的因果效应大小”。它用来在候选图之间比较谁更合理,而不是用来给单条边效应定强度。因果效应强度要用另外的估计(如do-演算、干预实验、效应估计)来做;BIC只负责在结构层面选边。

为何常见:分数高→关系强,这种直觉在监督学习里常见,但BIC是模型选择标准,不是效应量估计器。

误区我以为同一个马尔可夫等价类里的DAG只是箭头方向不一样,边的骨架和数量都一模一样,所以输出哪张都无所谓。

正解同骨架是定义的一部分,但并非“怎么定向都行”。只有不形成新V结构的那些方向调整才被允许。一旦某个三元结构会是V结构(碰撞点),它的方向就被数据锁定——CPDAG里连成无向边的部分才是真正无法定向的边。随意选一个成员当“真图”会误导因果结论。

为何常见:平时看的例子大多是3个变量的简单链条,方向翻转不影响骨架,容易让人忽略V结构的锚定作用。

面试题

Q1. GES中的“G”代表什么含义?

单选题 · easy

  • A.贪婪地选分数增量最大的操作← 正确答案
  • B.把所有候选图全部枚举一遍
  • C.使用梯度下降更新网络参数
  • D.对图结构做全局随机采样

答案:A。GES 的“G”指 Greedy(贪婪),即每一步只选当前BIC增量最大的操作。B 是穷举,C 是参数学习方法,D 是随机搜索,都不是GES的策略。

Q2. GES搜索发生在哪个空间?

单选题 · easy

  • A.单一DAG的完整空间
  • B.马尔可夫等价类空间← 正确答案
  • C.所有变量对的组合空间
  • D.潜在因子低维空间

答案:B。GES的“E”代表Equivalence,专门在马尔可夫等价类(CPDAG)上移动,而不是在单DAG空间。C和D是其他方法的搜索空间或降维空间。

Q3. 两个DAG马尔可夫等价的充要条件是?

单选题 · mid

  • A.节点数相同且边数相同
  • B.骨架相同且V结构相同← 正确答案
  • C.条件概率表完全相同
  • D.贝叶斯分数完全相同

答案:B。马尔可夫等价由“骨架+V结构”决定(Chickering)。A只要求边数,不够;C关注参数;D关注评分,而非数据结构本身。

Q4. GES前向阶段每步执行的贪心规则是?

单选题 · mid

  • A.随机加一条边并重新评分
  • B.选择BIC增量最大的合法加边← 正确答案
  • C.选择参数最少的模型结构
  • D.删除使似然最小的那条边

答案:B。前向阶段是“增边”阶段,每步在所有合法加边操作里选BIC增量最大的那一个。A是随机,C只求简,D是删边阶段的操作方向。

Q5. 下列哪些是GES两阶段的正确描述?

多选题 · mid

  • A.前向阶段只增边不删边← 正确答案
  • B.后向阶段只删边不增边← 正确答案
  • C.两阶段都会重新计算BIC← 正确答案
  • D.两阶段都使用随机游走

答案:ABC。GES分为前向(只加边)和后向(只删边),每一步都用BIC增量判断是否继续,因此ABC正确。D说随机游走,与贪婪策略矛盾。

Q6. BIC公式中的惩罚项主要作用是?

单选题 · mid

  • A.防止模型过度复杂导致过拟合← 正确答案
  • B.让所有图的分数变成正数
  • C.加快梯度反向传播速度
  • D.消除数据中的异常噪声值

答案:A。惩罚项随参数个数和样本量增长,压制“靠堆参数硬拟合”的复杂图。它不负责去噪、提速或改符号。

Q7. 为什么在等价类上搜索比单一DAG搜索更高效?

单选题 · hard

  • A.等价类空间更小,冗余移动更少← 正确答案
  • B.每次移动只改变一条边的方向即可
  • C.不需要为任何候选图计算BIC
  • D.每次操作可以并行处理所有节点

答案:A。单一DAG空间中有大量互为等价的冗余节点,搜索会重复访问“换汤不换药”的邻居;等价类空间压缩了这些冗余,每次移动相当于一整类图同步更新。B、C、D都与GES的实际机制不符。

Q8. 关于GES大样本一致性的正确表述有?

多选题 · hard

  • A.样本无穷时以概率1找到真实等价类← 正确答案
  • B.有限样本下仍可能输出局部最优← 正确答案
  • C.样本越大计算代价指数增长
  • D.需要忠实性等正则条件才能成立← 正确答案

答案:ABD。A是一致性结论;B是贪婪在有限样本下的普遍局限;D是理论成立的前提(忠实性、充分统计量等)。C虽“样本越多计算越重”,但并非一致性的表述,复杂度也非严格的指数增长。

Q9. CPDAG中无向边的含义是?

单选题 · extreme

  • A.该边在所有DAG中方向都不确定
  • B.该边两个方向在数据上无法区分← 正确答案
  • C.该边已被删除不用参与建模
  • D.该边只属于尚未搜索到的DAG

答案:B。CPDAG用无向边记录“方向无法由观测数据识别”的边;等价类中的不同DAG会在这些边上给出不同方向。A过于绝对——某些DAG里它是有向的;C和D都混淆了无向边与不存在边。

Q10. 下列哪些属于GES的典型实践应用?

多选题 · easy

  • A.从观测数据恢复因果结构← 正确答案
  • B.支持可解释AI决策分析← 正确答案
  • C.直接替代所有深度学习分类器
  • D.用于安全对齐中的链路识别← 正确答案

答案:ABD。GES输出因果图,可用于结构恢复、可解释分析和安全对齐中的因果链路识别;它不是通用分类器,C明显错误。