想象你是一位刚上任的镇长,对镇上一千位居民的人际关系一无所知。你让秘书画了一张“关系草图”:任何两位居民之间都先连一条线,假设他们可能直接认识。接下来,你设计了一套“引荐测试”——请某个中间人暂时离开,观察另外两人是否还保持往来。如果离了中间人两人就不再来往,说明他们只是点头之交,可以删线;如果中间人不在场他们依然热络,那才是真正的直接友谊。经过一轮又一轮测试,草图上的线越删越少,最终留下的无向关系图,就是这座小镇人脉的“骨架”。这个从“人人相连”到“删线成骨”的过程,正是因果发现领域里鼎鼎大名的骨架发现(Skeleton Discovery)。

岗位关联

理解骨架发现,就掌握了 PC、FCI 等主流因果发现算法的地基。无论你做可解释 AI、根因分析还是因果推断,先学会“画对骨架”,才谈得上后续方向定向的准确性。

目录
  1. 可视化演示
  2. 背景与目标
  3. 独立性检验
  4. 核心机制d-分离
  5. PC骨架搜索
  6. 正确性与复杂度
  7. FCI算法变体
  8. 实战与小结
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

骨架发现阶段以完全无向图为起点,逐步删除通过条件独立性检验的边,最终得到反映变量间直接依赖关系的无向骨架,是P... 切换模式查看不同维度。

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

骨架发现的初:核心原理 动态展示关键流程与数据流动 交互控件调节参数实时渲染 f(x) = transform(x) 核心概念的可视化呈现

背景与目标

镇长到岗第一天,面对全镇一千位居民,他让秘书画了一张“关系草图”:任何两人之间都先连一条线,假设彼此可能直接认识。这张草图像一张铺满暗线的地图,看似鲁莽,却暗藏智慧——在一个没有先验知识的起点上,先把所有可能性摆出来,再靠证据一条条砍掉。这正是骨架发现的起点:完全无向图。

在真实数据里,变量之间的关系不会自己长出来。基于约束的因果发现方法用一个极简但坚定的思路:把问题转化为“谁与谁之间存在直接依赖关系”。这一步产出的无向图就是有向无环图(DAG)的骨架。PC 算法与 FCI 算法都从这里起跑——如果骨架画错了,后续方向定向就全错了。

形式化地说,一个 DAG 的骨架就是把所有有向边抹去方向后的无向图。边存在,说明两个变量之间存在不依赖其他中间变量的统计关联。骨架发现不负责判断“X 是不是 Y 的原因”,只负责回答“X 和 Y 之间到底有没有边”。用邻接矩阵可以这样表示:

镇长把“疑似朋友线”先画满全镇,再请统计顾问一条一条验证。这张标注了“直接认识”的无向网络,虽然暂时还看不出谁是大哥谁是小弟,但已经把人脉的骨架勾勒出来。接下来,顾问要设计一套“中间人测试”,来剔除那些靠引荐认识的点头之交。

Mij={1,Xi 与 Xj 之间有边0,否则\displaystyle M_{ij} = \begin{cases} 1, & X_i \text{ 与 } X_j \text{ 之间有边} \\ 0, & \text{否则} \end{cases}
一句话:这是一张“是否有边”的 0-1 查表,是骨架的数学画像。
  1. 矩阵元素第 i 行第 j 列记录了变量 \(X_i\) 与 \(X_j\) 之间是否存在一条无向边。
    MijM_{ij}
  2. 取值为 1存在边时记为 1,表示两个变量有直接依赖关系。
    Mij=1  ⟺  (Xi,Xj)∈EM_{ij} = 1 \iff (X_i, X_j) \in E
  3. 取值为 0不存在边时记为 0,对应“删线”后的结果。
    Mij=0  ⟺  无边M_{ij} = 0 \iff \text{无边}

独立性检验

镇长很快发现,单看两人见面次数不能证明是真朋友。张三和李四天天在茶馆碰头,其实都是因为王五组的局。于是镇长设计了“引荐测试”:让王五离开一段时间,再观察张三和李四还会不会主动约茶。不会?说明张三和李四的关系全靠王五维系,这条线就该删。

把“引荐测试”结构化:设 X 和 Y 是两个嫌疑变量,Z 是潜在的中间人。如果“在知道 Z 取值的前提下,X 的信息不再给 Y 提供任何额外信息”,我们就说 X 和 Y 在给定 Z 时条件独立。它的数学定义是:

在样本上检验条件独立,离散变量常用 \(G^2\) 卡方检验,连续变量常用偏相关检验。核心是算出一个 p 值,再与预设的显著性水平 \(\alpha\) 比较。p 大于 \(\alpha\),就认为“找不到足够证据说明它们条件相关”,于是按保守原则删边。这里的 \(\alpha\) 就像“引荐测试”的容忍度:容忍度越低,越不容易误删真朋友,但也更容易漏掉该删的假关系。

镇长的引荐测试,在因果发现里就是一把反复使用的尺子。每一条疑似边都要接受一次或多次测试,只要有一次测试判定“完全靠中间人维系”,这条线就从草图中消失。

P(X,Y∣Z)=P(X∣Z) P(Y∣Z)\displaystyle P(X, Y \mid Z) = P(X \mid Z) \, P(Y \mid Z)
一句话:给定 Z 后,X 和 Y 的联合分布可以被拆成各自条件概率的乘积,说明 Z 已经“解释”了它们之间所有的关联。
  1. 联合条件概率这是“Z 已知时,X 和 Y 同时取某值”的概率。
    P(X,Y∣Z)P(X, Y \mid Z)
  2. 分解成乘积等式右侧写成“Z 已知时 X 的概率”乘以“Z 已知时 Y 的概率”,是独立性的标志。
    P(X∣Z) P(Y∣Z)P(X \mid Z) \, P(Y \mid Z)
  3. 独立的含义一旦 Z 固定,知道 X 也不会改变 Y 的分布,说明 X 对 Y 没有额外信息贡献。
    X⊥ ⁣ ⁣ ⁣⊥Y∣ZX \perp\!\!\!\perp Y \mid Z

核心机制d-分离

测试并没有看起来那么简单。有些“中间人”很特殊:他在场时,两个人反而不交流;他一走,两个人反而频繁咬耳朵。比如同时暗恋一个人的两个情敌,暗恋对象在场时他俩互不理睬,暗恋对象一离开,两人反而会互相通气。这类特殊结构下,条件独立的结论要反过来读。

这就是图论里的 d-分离(d-separation)。它把三元组分成两类:链式 \(A \to B \to C\) 和分叉 \(A \leftarrow B \to C\) 中,B 是“信息中转站”,给定 B 会阻断路径;对撞结构 \(A \to B \leftarrow C\) 中,B 是“信息交汇点”,给定 B 反而打通了 A 与 C 之间的新联系。

骨架发现真正依赖的是“忠实性”假设:如果数据由图 G 生成,那么 G 中 d-分离的性质一定会以条件独立的形式反映在数据里。用符号写就是:

镇长终于明白,光把中间人请走还不够,还得看清中间人到底是“引荐人”还是“暗恋对象”。d-分离就是这份人际拓扑学的说明书,它告诉镇长哪些情况下“请走中间人”能测出真朋友,哪些情况反而会测出另一些秘密。

X⊥dY∣Z  ⟹  X⊥ ⁣ ⁣ ⁣⊥Y∣Z\displaystyle X \perp_d Y \mid Z \implies X \perp\!\!\!\perp Y \mid Z
一句话:图上被阻断的路径,在数据里一定表现为条件独立——这是整个骨架发现成立的前提。
  1. 图上的分离左侧表示在因果图中,所有连接 X 与 Y 的路径都被 Z 阻断。
    X⊥dY∣ZX \perp_d Y \mid Z
  2. 蕴含关系箭头表示“只要图上说分离,数据上就必然独立”。
      ⟹  \implies
  3. 数据上的独立右侧是我们真正能通过统计检验验证的事实。
    X⊥ ⁣ ⁣ ⁣⊥Y∣ZX \perp\!\!\!\perp Y \mid Z

PC骨架搜索

镇长手绘的草图有十万条线,他担心单凭一个中间人挡不住复杂的牵线关系——万一张三和李四之间隔着两位中间人呢?于是镇长定下规矩:先从一个中间人问起,再逐步增加到两个、三个,直到把所有可能的组合都问一遍。问完一轮,删掉一批线,再进入下一轮。

这就是 PC 算法骨架阶段的序贯搜索。令 \(k=0\) 表示条件集为空,\(k=1\) 表示单个条件变量,依此类推。对每一对“仍然相邻”的节点 \((i,j)\),PC 算法只在 \(i\) 的邻居(去掉 \(j\) 自己)中挑选大小为 \(k\) 的子集作为候选条件集。候选集的集合写作:

每删除一条边,邻居集合就发生变化,下一轮就天然避开已经被断开的节点。这种“当前邻接集裁剪”让算法在稀疏网络上非常高效。当所有边都找不到符合条件的候选集时,算法终止,骨架完成。注意,那个让边删除的分离集(separating set)一定要保存下来——它是下一步方向定向的弹药。

镇长按这个流程办,先删掉了那些“一个中间人就能解释”的虚交,再逐渐查更复杂的圈子。每删一条线,下一轮的调查对象就少一分。最终剩下的每一对关系,都经得起“任意组合中间人”的考验,真正称得上直接往来。

Sk(i,j)={S⊆Adj⁡(i)∖{j}:∣S∣=k}\displaystyle \mathcal{S}_k(i,j) = \left\{ S \subseteq \operatorname{Adj}(i)\setminus\{j\} : |S| = k \right\}
一句话:在第 k 轮调查中,候选“中间人组合”只从当前邻居里挑,且恰好挑 k 个人。
  1. 邻居集合\(\operatorname{Adj}(i)\) 是节点 i 当前仍然相连的邻居集合,它随删边动态缩小。
    Adj⁡(i)\operatorname{Adj}(i)
  2. 排除对方\(\setminus\{j\}\) 表示候选中间人不能包含正在被测试的节点 j 自己。
    Adj⁡(i)∖{j}\operatorname{Adj}(i)\setminus\{j\}
  3. 子集大小\(|S| = k\) 约束每个候选条件集恰好包含 k 个变量,k 从 0 逐级递增。
    ∣S∣=k|S| = k
  4. 整体含义枚举所有满足条件的子集,逐个做条件独立检验,直到找到一个能让 i、j 独立的 S。
    ∃S∈Sk(i,j):Xi⊥ ⁣ ⁣ ⁣⊥Xj∣S\exists S \in \mathcal{S}_k(i,j): X_i \perp\!\!\!\perp X_j \mid S

正确性与复杂度

但镇长听了统计顾问的汇报后开始担心:如果一次测试在样本里恰好出差错,会不会导致后面全乱套?顾问直言:会。一个误删的边,就好比把一条原本真有的隐秘通道从地图上画没了,之后的探路都会绕远路或走进死胡同。

在理想条件下——数据忠实于真实图,且独立性检验是一个完美 oracle——PC 的骨架搜索被证明能精确恢复真实骨架,这叫检测一致性。但现实中的有限样本会让 p 值随机波动,误判率只能靠显著性水平控制,无法根除。

复杂度的代价也必须正视。最坏情况下,每一对节点都要尝试所有可能条件集。n 个变量的完全无向图有 \(n(n-1)/2\) 条边,每条边最多要检验从 0 阶到 \(n-2\) 阶的所有条件集,总检验次数约为:

镇长权衡后决定:测试宁慢勿错,并且请顾问优先调查“朋友圈小”的居民——他们的关系更容易被几个中间人完全解释。这种策略,正是稀疏性红利在真实世界的投影。

T(n)≤n(n−1)×∑k=0n−2(n−2k)=n(n−1)×2n−2=O(n22n−2)\displaystyle T(n) \leq n(n-1) \times \sum_{k=0}^{n-2} \binom{n-2}{k} = n(n-1) \times 2^{n-2} = \mathcal{O}\left(n^2 2^{n-2}\right)
一句话:指数级的最坏复杂度,解释了为什么骨架发现必须建立在“真实网络稀疏”的信念之上。
  1. 节点对数量\(n(n-1)\) 是“谁和谁之间”的有序节点对数,约等于节点对的二倍。
    n(n−1)n(n-1)
  2. 组合数\(\binom{n-2}{k}\) 表示从除 i、j 外的 \(n-2\) 个节点中选 k 个做条件集的方案数。
    (n−2k)\binom{n-2}{k}
  3. 逐阶求和把 k 从 0 加到 \(n-2\),完整覆盖所有可能的条件集大小。
    ∑k=0n−2(n−2k)\sum_{k=0}^{n-2} \binom{n-2}{k}
  4. 二项式定理化简所有组合数加起来恰好等于 \(2^{n-2}\),于是出现指数因子。
    ∑k=0n−2(n−2k)=2n−2\sum_{k=0}^{n-2} \binom{n-2}{k} = 2^{n-2}

FCI算法变体

正当镇长的调查有条不紊推进时,有人提醒:镇上有几位极其低调的富豪,从不参加聚会,却总在幕后牵线。他们不在草图上,却影响着你看到的每一场“偶然相遇”。若不考虑他们,镇长很容易把一段真实关系误判为“完全靠引荐”而删掉。

当存在未观测到的隐变量时,骨架发现会面临系统性偏差。PC 算法的激进删除策略变得危险。FCI 算法因此被设计出来:它不直接使用当前邻接集,而是构造一种更保守的候选集合——可能依赖集(Possibly-D-SEP)。FCI 在骨架阶段只删除那些“在任何可能隐藏变量下都不可能相关”的边。候选条件集的范围写作:

因此 FCI 输出的不再是普通无向骨架,而是带有端点符号的“部分骨架”(partially oriented skeleton)。端点可以是箭头、圆点或空标记,用来表达“这个方向可能成立”或“此处可能有隐变量”等不确定信息。

镇长采纳了顾问的方案:既然幕后富豪无法全部点名,那就不轻易断言任何一段关系是“纯引荐”。地图上多留几条虚线,总比把真关系一笔勾销要稳妥。这种保守,正是 FCI 在复杂现实里存活的智慧。

PD-SEP⁡(X)={Y:∃ 路径 X⇝Y, 其中每个对撞点都是 X 或 Y 的祖先}\displaystyle \operatorname{PD-SEP}(X) = \left\{ Y : \exists \text{ 路径 } X \leadsto Y,\ \text{其中每个对撞点都是 } X \text{ 或 } Y \text{ 的祖先} \right\}
一句话:凡是可能被隐藏变量撑起直接联系的边,FCI 都宁可保留,只把最没有争议的边删掉。
  1. 存在路径\(X \leadsto Y\) 表示从 X 到 Y 存在一条可通达路径。
    X⇝YX \leadsto Y
  2. 对撞点限制路径上的每个对撞点都必须是 X 或 Y 的祖先,这是 FCI 对“是否可能相关”的保守判据。
    每个对撞点∈Anc⁡({X,Y})\text{每个对撞点} \in \operatorname{Anc}(\{X, Y\})
  3. 集合整体把所有满足条件的 Y 收集起来,得到比普通邻居更大的候选池。
    PD-SEP⁡(X)\operatorname{PD-SEP}(X)

实战与小结

半年后,镇长终于拿到了那张“直接往来地图”。他请数据分析师把整个流程写成代码,以后每月自动更新一次,再也不用人工翻户口本。

这里我们用 Python 从线性高斯数据出发,实现一个微型骨架发现器。数据背后的真实因果结构是:\(B\) 直接影响 \(A\)、\(C\)、\(D\),而 \(A\) 直接影响 \(E\)。条件独立性用偏相关系数检验。偏相关系数的计算公式是:

运行代码后会看到:算法从完全图开始,像镇长一样一轮一轮“问中间人”,最终保留下来的四条边恰好是 AB、BC、BD、AE——与真实结构完全一致。镇长把这张图贴在县政府大厅,说:这就是小镇人脉的骨架。

rXY⋅Z=rXY−rXZ rYZ(1−rXZ2)(1−rYZ2)\displaystyle r_{XY \cdot Z} = \frac{r_{XY} - r_{XZ}\, r_{YZ}}{\sqrt{(1 - r_{XZ}^2)(1 - r_{YZ}^2)}}
一句话:先扣除 Z 对 X、Z 对 Y 的线性影响,再看剩下残差之间是否还有相关性。
  1. 分子从 X 与 Y 的总相关中减去 Z 分别对两者的线性贡献,得到“净关联”。
    rXY−rXZ rYZr_{XY} - r_{XZ}\, r_{YZ}
  2. 分母根号项把残差的尺度归一化,保证偏相关系数仍落在 \([-1, 1]\)。
    (1−rXZ2)(1−rYZ2)\sqrt{(1 - r_{XZ}^2)(1 - r_{YZ}^2)}
  3. 整体如果 \(r_{XY \cdot Z}\) 接近 0,说明控制 Z 后 X 与 Y 不再相关,支持条件独立。
    rXY⋅Z≈0  ⟹  X⊥ ⁣ ⁣ ⁣⊥Y∣Zr_{XY \cdot Z} \approx 0 \implies X \perp\!\!\!\perp Y \mid Z

AI 应用场景

电商推荐中的因果分解

阶段:特征工程与因果结构学习

解决的问题:广告点击与购买转化之间的高相关可能来自用户活跃度等混杂变量。传统相关系数过滤会把关联误当因果,导致投放预算浪费。骨架发现先在“点击、活跃度、品类偏好、购买”之间画完全图,再做条件独立检验,找出哪些特征与转化存在直接边。

具体案例:某电商团队用因果骨架定位“加购→下单”的直接依赖,发现“浏览时长”在给定加购行为后与下单条件独立,于是把它从反事实评估模型中剔除,重新分配流量后 ROI 提升约 12%。

医疗电子病历的变量精简

阶段:临床特征筛选与可解释建模

解决的问题:医生面对上千份检验指标,想找到疾病的直接相关因素。许多指标由共同病理过程驱动,相互关联形成一团乱麻。骨架发现可以构建无向网络,快速剔除在给定核心指标后条件独立的冗余变量。

具体案例:在心衰院内死亡率预测研究中,团队用骨架发现提取直接相邻的 5 个生理指标,把模型维度从 70 维降到 10 维,同时 AUC 保持稳定,且医生一眼就能看懂变量关系。

微服务故障根因分析

阶段:可观测性与根因定位

解决的问题:微服务调用链上一个服务抖动会顺着链路传播,导致所有下游指标同时尖峰,相关矩阵一片热闹。骨架发现可以删掉通过中间服务间接相关的假边,留下真正直接依赖的服务链路,让排查从“全链路搜索”变成“沿骨架定向”。

具体案例:在订单系统故障中,AIOps 平台用骨架发现快速锁定“库存服务→订单服务”这条直接依赖边,跳过了十几个相关但间接的服务监控面板,MTTR 缩短近一半。

Python 演示

python70 行
import numpy as npfrom itertools import combinationsfrom scipy.stats import norm rng = np.random.RandomState(42)N = 3000 # 真实结构: B -> A, B -> C, B -> D, A -> EB = rng.normal(size=N)A = 1.0 * B + rng.normal(size=N) * 0.5C = 1.0 * B + rng.normal(size=N) * 0.5D = 1.0 * B + rng.normal(size=N) * 0.5E = 0.9 * A + rng.normal(size=N) * 0.4 data = np.column_stack([A, B, C, D, E])names = ['A', 'B', 'C', 'D', 'E']n = data.shape[1]  def residuals(target, regressors):    """Y - Z @ beta"""    X = data[:, regressors]    beta, _, _, _ = np.linalg.lstsq(X, data[:, target], rcond=None)    return data[:, target] - X @ beta  def partial_corr(x, y, cond):    if len(cond) == 0:        return np.corrcoef(data[:, x], data[:, y])[0, 1]    rx = residuals(x, cond)    ry = residuals(y, cond)    return np.corrcoef(rx, ry)[0, 1]  def cond_indep(x, y, cond, alpha=0.05):    r = partial_corr(x, y, cond)    z = 0.5 * np.log((1 + r) / (1 - r))    se = 1.0 / np.sqrt(N - 3 - len(cond))    p = 2 * (1 - norm.cdf(abs(z) / se))    return p > alpha  adj = np.ones((n, n), dtype=bool) - np.eye(n, dtype=bool)sep = {}k = 0while True:    changed = False    pairs = [(i, j) for i in range(n) for j in range(i + 1, n) if adj[i, j]]    for i, j in pairs:        neighbors = [x for x in range(n) if adj[i, x] and x != j]        if len(neighbors) < k:            continue        for cond in combinations(neighbors, k):            if cond_indep(i, j, list(cond)):                adj[i, j] = adj[j, i] = False                sep[(i, j)] = list(cond)                changed = True                break    k += 1    if not changed or k > n - 2:        break print("留存的边:")for i in range(n):    for j in range(i + 1, n):        if adj[i, j]:            print(f"  {names[i]} -- {names[j]}")print("删除的边与分离集:")for key, val in sep.items():    print(f"  {names[key[0]]} -- {names[key[1]]}  分离集: {[names[c] for c in val]}")
目的:从线性高斯模拟数据中,用偏相关显著性检验完成 PC 算法的骨架发现,最终输出保留边与被删除边及其分离集。
  1. data = np.column_stack([A, B, C, D, E])把五个变量拼成数据矩阵,每列是一个变量。
  2. def residuals(target, regressors):用最小二乘回归把目标变量中的“中间人影响”剥离掉,得到残差。
  3. p = 2 * (1 - norm.cdf(abs(z) / se))用 Fisher z 变换计算双侧 p 值,p 大于 alpha 判定为条件独立。
  4. for cond in combinations(neighbors, k):枚举当前阶数 k 下的所有候选条件集,这是 PC 序贯搜索的核心。
  5. adj[i, j] = adj[j, i] = False命中条件独立时双向删除边,并立刻将条件集记入分离集字典。
  6. if not changed or k > n - 2:一轮没有删任何边,或条件集已经大到不可能再有用时,终止循环。

常见误区

误区我在数据里算了一下 X 和 Y 的皮尔逊相关系数只有 0.05,觉得肯定没关系,就直接把这条边删掉了。

正解边际相关近似为零,不代表条件相关为零。在链条结构中,边际相关可能很大但条件独立;在对撞结构中,边际相关可能为零但给定某个共同后代后反而条件相关。骨架发现的核心不是看边际相关,而是系统性测试条件独立,必须在条件集的配合下决定是否删边。

为何常见:默认了“两个变量关系弱 = 没有关系”,可现实中很多变量是通过第三方产生联系的,单看表面相关系数很容易被误导。

误区既然删边要做条件独立检验,那把其他所有变量都放进条件集,测试更全面,应该更好。

正解条件集过大会引发两个问题:一是高维条件下样本稀少,检验统计量漂移、p 值失真;二是大量检验引入多重比较误差。PC 算法坚持从小条件集开始,是因为如果一个小条件集就能解释这对变量的关联,就没有必要动用大动干戈的条件集。

为何常见:直觉上“控制更多变量”更严谨,但统计功效在高维空间里会急剧崩溃,这是“维度灾难”在因果发现中的体现。

误区骨架发现完成后我拿到一张无向图,就以为 X—Y 表示“X 导致 Y”。

正解无向边只说明两个变量存在直接依赖关系,但说不清箭头朝哪。方向定向是后续阶段基于对撞结构(v-structure)和机械规则完成的。骨架是“地图轮廓”,不是“导航路线”。

为何常见:做汇报时总想把无向边脑补成因果方向,忽视了方法本身的阶段分工,也容易向业务方过度承诺因果结论。

误区骨架发现只要输出邻接矩阵就够了,那个分离集集合(sep)算法结束就没用了。

正解分离集是方向定向的钥匙。只有知道每条边是在哪个条件集下被删除的,才能识别对撞结构:如果 X 与 Y 在给定某个 S 时被删边,而 S 不包含 Z,那么很可能是 X 与 Y 在对撞点 Z 处汇合。扔掉分离集等于扔掉定向阶段的全部线索。

为何常见:只关注“最终图”,不关注从完全图到骨架的删边过程,忽略了过程元数据对后续步骤的价值。

误区FCI 就是把 PC 换个名字,最后也能输出一张普通无向图。

正解FCI 在隐变量下必须更保守。它输出的“部分骨架”含有 o-* 等端点符号,表示该端点可能是箭头、圆点或空标记,代表不同的因果含义。强制转成无向图会丢失隐变量信息。

为何常见:把 FCI 简单理解为 PC 的一个变体,以为两者输出形态完全相同,忽略了隐变量假设带来的本质差异。

面试题

Q1. 骨架发现的核心目标是什么?

单选题 · easy

  • A.确定变量间的因果方向
  • B.找出直接依赖的无向边← 正确答案
  • C.拟合完整的联合概率分布
  • D.对所有变量做聚类降维

答案:B。骨架发现只输出无向骨架,核心是判断哪些变量之间存在直接依赖的边。方向定向是后续阶段的工作;C 是概率建模任务,D 是特征工程任务。就像镇长画“直接往来地图”,只画线不标箭头。

Q2. 基于约束的骨架发现,初始图通常是?

单选题 · easy

  • A.完全无向图← 正确答案
  • B.完全有向图
  • C.完全空图
  • D.随机森林图

答案:A。算法以“所有节点两两可能有边”的完全无向图作为起点,再通过条件独立性检验删边。空图没有候选边可以检验,有向图在骨架阶段也无需方向信息。

Q3. 条件独立 X⊥Y|Z 的数学定义是?

单选题 · mid

  • A.P(X,Y)=P(X)P(Y)
  • B.P(X|Z)=P(Y|Z)
  • C.P(X,Y|Z)=P(X|Z)P(Y|Z)← 正确答案
  • D.E[XY|Z]=E[X]E[Y]

答案:C。C 是标准定义:给定 Z 后,X 和 Y 的联合分布可分解为各自条件概率的乘积。A 是边际独立,不涉及 Z;B 是条件概率相等,不等价于联合分解;D 只是矩条件,比分布独立弱。

Q4. 在链式结构 A→B→C 中,给定 B 后 A 与 C 的关系是?

单选题 · mid

  • A.仍然相互独立
  • B.条件独立← 正确答案
  • C.更加依赖
  • D.完全无关

答案:B。B 是链条中的非对撞节点,给定 B 会阻断 A 与 C 之间的信息路径,因此二者条件独立。D 的“完全无关”更接近无条件概念,且表述绝对化,不是条件独立的准确说法。

Q5. 以下哪些结构中,给定节点 B 会使 A 与 C 条件独立?

多选题 · mid

  • A.A→B→C← 正确答案
  • B.A←B→C← 正确答案
  • C.A→B←C
  • D.A−B−C 且 B 节点类型未知

答案:AB。链式(A)和分叉(B)中 B 都是非对撞节点,给定 B 会阻断路径;对撞(C)中给定 B 反而激活 A 与 C 的关联;D 中 B 类型未知,无法判断,不能作为确定性答案。

Q6. PC 算法骨架阶段记录分离集(separating set)的主要目的是?

单选题 · hard

  • A.降低条件独立检验的计算量
  • B.为后续方向定向提供依据← 正确答案
  • C.计算模型的置信区间
  • D.判断隐变量的个数

答案:B。分离集记录的是“哪条边在什么条件集下被删除”,这是后续识别对撞结构、确定边方向的关键线索。计算量主要由邻居集合裁剪控制,与分离集的记录无关。

Q7. 关于 PC 算法的序贯搜索,下列说法正确的是?

多选题 · hard

  • A.条件集大小从 0 阶开始递增← 正确答案
  • B.只对仍相邻的节点对做检验← 正确答案
  • C.条件集越大检验功效一定越高
  • D.候选条件集从当前邻居中抽取← 正确答案

答案:ABD。PC 从小条件集开始,随着邻接图不断删边,每轮只检查仍相邻的节点对,候选集来自当前邻接集。C 错误,条件集过大会导致维度灾难,统计功效反而急剧下降。

Q8. FCI 算法比 PC 更保守的根本原因是?

单选题 · mid

  • A.存在未观测的隐变量← 正确答案
  • B.计算资源不足
  • C.数据量太大
  • D.不需要准确骨架

答案:A。FCI 专门应对隐变量干扰。隐变量可能撑起本来看不见的直接关联,因此 FCI 用更保守的候选条件集,避免误删真实边,这与计算资源或数据量无关。

Q9. 在忠实性假设和完美条件独立 oracle 下,PC 算法的骨架发现结果是?

单选题 · extreme

  • A.一定等于真实因果图的无向骨架← 正确答案
  • B.只有一半边正确
  • C.包含所有伪边
  • D.与样本量有关

答案:A。忠实性保证图上 d-分离与数据条件独立一一对应,oracle 保证检验不会犯错。二者同时成立时,PC 的骨架搜索被证明可以精确恢复真实骨架,这是该方法的理论基石。

Q10. 实践中影响骨架发现误判的因素包括?

多选题 · mid

  • A.有限样本导致的检验波动← 正确答案
  • B.显著性水平 alpha 的选择← 正确答案
  • C.条件集维度对统计功效的影响← 正确答案
  • D.变量的名称长度

答案:ABC。样本量决定 p 值稳定性,alpha 决定误删与漏删的权衡,条件集维度直接影响高维下检验的可靠性。变量名称只是人的标签,与统计性质无关。