日期:2026-09-02
严重性:高。它很可能让 PRIOS完整方法学与结果报告.md §6.4 的整段结论作废。
主检验(清醒 vs 麻醉,p=0.0625)不受影响,理由见 §4。
prios_code/prios_分析.py 里,观测图和零模型对「谁能发出边」的约束不一致。
观测图(weighted_graph):一条有向边表示「刺激 A 之后在 B 上测到诱发反应」。
所以出边只可能来自被刺激过的电极:
srcs = [e for e in p if e in idx] if C.EDGE_FROM_BOTH else [p[0]]
...
for s in srcs:
W[idx[s], idx[c]] = max(W[idx[s], idx[c]], abs(pk[i]))
从没被刺激过的电极,那一行全是零。
零模型(null_stats,修正前):把边重排到全部 n(n−1) 个有序对上:
prs = [(i, j) for i in range(n) for j in range(n) if i != j]
一个没有出边的节点不可能落在环上。 零模型的可用源集合比观测图大,
它的环占比就被系统性抬高,于是 CE_excess = 观测 − 零模型 被系统性压低。
压多少,取决于「被刺激的电极占全部节点的比例」(下称源占比)。
图建在全部共同电极上(W = np.zeros((len(chans), len(chans)))),
所以源占比在 PRIOS 各被试间从 0.43 变到 1.00——差异很大。
用 prios_results_旧零模型_2026-08-29.json(已归档于 git 历史的 pre-migration tag,
不在当前工作树),取 d*=0.05 清醒条件:
| 被试 | 节点数 | 刺激对数 | 源占比 | 清醒 CE_excess | 零模型基线 |
|---|---|---|---|---|---|
| PRIOS01 | 42 | 36 | 1.00 | +0.032 | 0.515 |
| PRIOS09 | 50 | 44 | 1.00 | +0.051 | 0.656 |
| PRIOS02 | 69 | 30 | 0.87 | −0.147 | 0.892 |
| PRIOS05 | 63 | 23 | 0.73 | −0.382 | 0.838 |
| PRIOS04 | 56 | 15 | 0.54 | −0.385 | 0.753 |
| PRIOS03 | 61 | 13 | 0.43 | −0.380 | 0.826 |
corr(源占比, 清醒 CE_excess) = +0.908
仅有的两个 CE_excess 为正的被试,恰好就是仅有的两个源占比 = 1.00 的被试。
(源占比按 min(2×刺激对数, 节点数)/节点数 估算,是上界;
重跑后 diag.n_src 会给出精确值。)
零模型源限制偏差检验.py:60 个节点,密度 0.05,图里没有任何真实结构,
只有随机边。唯一保留的差异就是「观测图限制源、零模型不限制」。
| 源占比 | 观测 CE | 现行零模型 | 凭空产生的超出量 | 修正后零模型 | 修正后超出量 |
|---|---|---|---|---|---|
| 1.00 | 0.766 | 0.809 | −0.043 | 0.809 | −0.043 |
| 0.87 | 0.694 | 0.809 | −0.115 | 0.706 | −0.012 |
| 0.73 | 0.643 | 0.809 | −0.166 | 0.602 | +0.041 |
| 0.54 | 0.457 | 0.809 | −0.352 | 0.447 | +0.011 |
| 0.43 | 0.369 | 0.809 | −0.440 | 0.368 | +0.001 |
对照:同密度随机无环图的 CE = 0.0000。环判定本身没写错, 所以上表不是判定 bug 造成的。
把这一列跟 §2 的真实数据并排看:
| 源占比 | 真实数据 | 纯随机仿真 |
|---|---|---|
| 1.00 | +0.032 | −0.043 |
| 0.87 | −0.147 | −0.115 |
| 0.73 | −0.382 | −0.166 |
| 0.54 | −0.385 | −0.352 |
| 0.43 | −0.380 | −0.440 |
形状和量级都对上了。 也就是说,一个完全没有递归结构的随机图, 在当前零模型下会产出和我们观测到的几乎一样的「负超出量」。
受影响:报告 §6.4 的逐条件零模型检验。 原文的结论是 「清醒 CE_excess 均值 −0.202(p=0.065),麻醉 −0.396(p=0.027,显著地比随机图更不递归)」。 这段现在必须当作待定——它很可能整个是零模型设定错误的产物, 而不是关于大脑递归结构的发现。
不受影响:主检验(清醒 vs 麻醉配对比较,Wilcoxon W=1.0,双侧 p=0.0625)。
理由是代码里两个条件用的是同一个电极交集和同一组匹配刺激对
(common = [c for c in L["clin"][1] if c in set(L["prop"][1])],
matched = {p: min(cnt["clin"][p], cnt["prop"][p]) ...}),
所以源集合在两条件间是逐位匹配的,偏差在做差时相消。
间接受影响:跨被试的可比性,进而是功效。
零模型基线在被试间从 0.515 漂到 0.892,
corr(节点数, 零模型基线) = +0.990。
n=69 的被试,其 CE_excess 最多只能到 +0.108,却能低到 −0.892——
正负空间严重不对称。这会往组间差里注入与假设无关的方差,吃掉功效。
零模型的候选边槽限制为「源是被刺激过的电极」的有序对, 与观测图遵守同一条生成约束。
已实施(prios_分析.py):
- weighted_graph 额外返回 src_idx / n_src
- null_stats 增加 src_idx 参数;为 None 时保持旧行为(留作对照)
- metrics 新旧两种零模型都算,修正版的键名带 _srcfix 后缀
两个都保留,是为了避免「换了算法才变好看」的嫌疑—— 对照就在同一个结果文件里,任何人都能自己比。
源集合取自「被刺激过的电极」这一结构事实,不随密度阈值化变化: 零模型要遵守的是与观测图同一条生成约束,不是阈值化后的残留。
冒烟测试(源占比 0.43,纯随机权重):
观测 CE = 0.379
旧零模型 (不限源) = 0.802 超出量 -0.423
新零模型 (限制源) = 0.362 超出量 +0.016
旧结果 prios_results_旧零模型_2026-08-29.json 与旧脚本 prios_分析_旧版备份.py
已归档于 git 历史(pre-migration tag),取回命令:
git show pre-migration:prios_code/prios_results_旧零模型_2026-08-29.json
git show pre-migration:prios_code/prios_分析_旧版备份.py
这是独立于源限制的另一个问题,同样吃功效。
密度规则标定.py(纯图论,不碰真实数据):
| 节点数 | 固定 d*=0.05 时的零模型基线 |
|---|---|
| 42 | 0.523 |
| 50 | 0.660 |
| 56 | 0.750 |
| 61 | 0.816 |
| 63 | 0.877 |
| 69 | 0.888 |
| 82 | 0.952 |
| 100 | 0.979 |
极差 0.455。 真实数据里的对应值是 0.515 → 0.892,
corr(节点数, 零模型基线) = +0.990,完全吻合。
后果是正负空间不对称:n=69 的被试其 CE_excess 最多只能到 +0.112, 却能低到 −0.888。这往组间差里注入了与假设完全无关的方差。
闸门⑤拦不住它:那道闸门只要求随机图 CE < 0.95,而 n=69 时基线是 0.888, 刚好压线通过。闸门检验的是「有没有到天花板」,不是「基线在被试间稳不稳」。
修法:把 d* 从固定常数改成随节点数走的规则 d* = k·ln(n)/n。
| 节点数 | k=0.34 时的 d* | 保留边数 | 零模型基线 |
|---|---|---|---|
| 42 | 0.030 | 52 | 0.183 |
| 56 | 0.024 | 75 | 0.160 |
| 69 | 0.021 | 98 | 0.186 |
| 82 | 0.018 | 121 | 0.174 |
| 100 | 0.016 | 155 | 0.161 |
基线极差从 0.455 降到 0.026。
诚实的附注:我扫 k 时每个点只跑了 10 次重复,所以 k 在 0.3–0.7 之间 各值的优劣差异有相当部分落在噪声里,「k=0.34 最优」这个具体数字不牢靠。 牢靠的是方向:这一族规则里随便取一个都比固定 d* 好一个数量级 (极差 0.03–0.16 对 0.455)。真要定 k,得加大重复次数重标。
而且这条规则不能事后直接套到现有结果上——我们已经看过哪些密度显著了 (敏感性分析里 d*=0.02 和 0.06 出了 p=0.031)。事后按这条规则重选密度, 等于用看过的结果挑参数。
正确做法:先用 ds004080 那 74 个清醒单态被试(那批数据里没有状态对比可偷看) 把 k 定死,写进预注册,再应用到状态对比上。
prios_code/重跑_源限制修正_2026-09-02.log。PRIOS06 仍按原闸门 3 排除,与旧版一致。
| 检查项 | 旧零模型 | 修正后 |
|---|---|---|
| corr(源占比, 清醒 CE_excess) | +0.969 | −0.316 |
| corr(节点数, 零模型基线) | +0.992 | −0.184 |
源占比依赖被消除了(n=6 时 −0.32 与零无法区分), 节点数对基线的系统性驱动也消除了。这是修正有效的直接证据。
(注:旧版这两个相关系数用的是精确的 n_src,比我先前用 2×刺激对数 估算的
+0.908 更高。估算是上界,实测更糟。)
d*=0.05,六个被试:
| 被试 | 节点 | 刺激源 | 源占比 | 清醒(旧) | 清醒(修正) | 麻醉(旧) | 麻醉(修正) |
|---|---|---|---|---|---|---|---|
| PRIOS01 | 42 | 41 | 0.98 | +0.067 | +0.072 | −0.152 | −0.145 |
| PRIOS02 | 69 | 44 | 0.64 | −0.198 | +0.121 | −0.415 | −0.041 |
| PRIOS03 | 61 | 20 | 0.33 | −0.375 | +0.163 | −0.435 | +0.118 |
| PRIOS04 | 56 | 24 | 0.43 | −0.320 | +0.087 | −0.678 | −0.154 |
| PRIOS05 | 63 | 34 | 0.54 | −0.369 | +0.006 | −0.756 | −0.331 |
| PRIOS09 | 50 | 50 | 1.00 | +0.080 | +0.080 | +0.088 | +0.125 |
| 旧零模型 | 修正零模型 | |
|---|---|---|
| 清醒均值 | −0.186 | +0.088,95% CI [+0.033, +0.143],6/6 为正,双侧 p=0.031 |
| 麻醉均值 | −0.391(显著为负) | −0.071,95% CI [−0.256, +0.113],2/6 为正,p=0.31 |
旧结论说「两态都没有正向超出、麻醉态显著地比随机更不递归」。 修正后是「清醒态有正向超出,麻醉态与零无法区分」。方向整个反了。
跨六个密度阈值看,修正零模型下:
| d* | 清醒均值 | 正号 | p | 麻醉均值 | p | 主检验均值差 | 同向 | p |
|---|---|---|---|---|---|---|---|---|
| 0.02 | +0.245 | 6/6 | 0.031 | +0.114 | 0.44 | +0.130 | 6/6 | 0.031 |
| 0.03 | +0.215 | 5/6 | 0.063 | +0.101 | 0.31 | +0.114 | 5/6 | 0.063 |
| 0.04 | +0.106 | 4/6 | 0.22 | −0.017 | 1.00 | +0.122 | 6/6 | 0.031 |
| 0.05(预注册) | +0.088 | 6/6 | 0.031 | −0.071 | 0.31 | +0.159 | 5/6 | 0.094 |
| 0.06 | +0.020 | 3/6 | 0.44 | −0.075 | 0.16 | +0.095 | 5/6 | 0.063 |
| 0.08 | −0.021 | 3/6 | 0.84 | −0.042 | 0.31 | +0.021 | 4/6 | 0.84 |
「清醒态有正向超出」只在 6 个密度里的 2 个上显著(0.02 与 0.05),不稳健。 均值随密度单调下降到零,这本身是预期的(密度越高越接近饱和、超出空间越小), 但它意味着这个结论强烈依赖阈值选择。
而且 n=6 时全部同号能达到的最好双侧 p 就是 0.03125。 所以 p=0.031 是功效天花板,不是强证据——它等价于「六个人方向全一致」,仅此而已。
| 旧零模型 | 修正零模型 | |
|---|---|---|
| d*=0.05(预注册主检验) | 5/6 同向,均值差 +0.205,W=1,p=0.0625 | 5/6 同向,均值差 +0.159,W=2,p=0.0938 |
方向、同向人数、逐被试符号全部不变(5 正 1 负,负的仍是 PRIOS09), 但 p 从 0.0625 变到 0.0938。
我先前判断「两条件源集合匹配、偏差在做差时相消,主检验不受影响」——
方向上对,程度上说过头了。原因是每个条件用的是自己那一侧的源集合
(pairs_used 在两条件间不完全相同,例如 PRIOS01 是 36 对 vs 34 对),
所以偏差只是大部分相消,不是完全相消。
总判决不变:两个 p 都没过预注册的 α=0.05,仍然是「不确认,不证伪,功效不足」。
修法是从结构论证推出来的,并且在看到修正后的真实数据之前就已经在
纯随机图上验证过(零模型源限制偏差检验.py 先跑,重跑在后)。
新旧两版结果都存在同一个 JSON 里,键名分别是 ce_excess 与 ce_excess_srcfix。
任何人可以自己比。
见 决定_节点集与密度规则_2026-09-02.md:预注册 §2 与报告 §4.1 都写明节点=双角色电极,
代码用的是全部共同通道,属实现不符规格。改正后重跑(重跑_双角色节点_2026-09-02.log)。
| 被试 | 原共同通道 | 双角色电极 | 仅记录未刺激(被剔除) |
|---|---|---|---|
| PRIOS01 | 42 | 41 | 1 |
| PRIOS02 | 69 | 44 | 25 |
| PRIOS03 | 61 | 20 | 41 |
| PRIOS04 | 56 | 24 | 32 |
| PRIOS05 | 63 | 34 | 29 |
| PRIOS09 | 50 | 50 | 0 |
| 被试 | 源占比 | 旧零模型基线 | 限源零模型基线 | 差 |
|---|---|---|---|---|
| 全部六人 | 1.00 | — | — | 0.0000 |
六个被试的新旧零模型逐位相同。这证明 §5 的源限制修正与节点集修正是同一个问题的两种修法, 节点集改对之后前者自动失效——正是决定文档里预期的结果。
| 全通道节点(旧,有缺陷) | 全通道 + 限源零模型 | 双角色节点(预注册规定) | |
|---|---|---|---|
| 清醒均值 | −0.186 | +0.088 | +0.106(6/6 为正,p=0.031) |
| 麻醉均值 | −0.391 | −0.071 | −0.024(2/6 为正,p=0.84) |
| 主检验同向 | 5/6 | 5/6 | 4/6 |
| 主检验均值差 | +0.205 | +0.159 | +0.130 |
| 主检验 W / p | 1 / 0.0625 | 2 / 0.0938 | 4 / 0.2188 |
| d* | 清醒均值 | 正号 | p | 麻醉均值 | 正号 | p | 主检验差 | 同向 | p |
|---|---|---|---|---|---|---|---|---|---|
| 0.02 | +0.249 | 6/6 | 0.031 | +0.045 | 3/6 | 0.44 | +0.203 | 6/6 | 0.031 |
| 0.03 | +0.232 | 6/6 | 0.031 | +0.126 | 3/6 | 0.44 | +0.106 | 5/6 | 0.16 |
| 0.04 | +0.159 | 5/6 | 0.063 | +0.025 | 3/6 | 0.56 | +0.135 | 5/6 | 0.16 |
| 0.05(预注册) | +0.106 | 6/6 | 0.031 | −0.024 | 2/6 | 0.84 | +0.130 | 4/6 | 0.219 |
| 0.06 | +0.095 | 4/6 | 0.56 | −0.079 | 1/6 | 0.31 | +0.174 | 6/6 | 0.031 |
| 0.08 | −0.067 | 1/6 | 0.44 | −0.185 | 1/6 | 0.22 | +0.118 | 4/6 | 0.22 |
三次修正把主检验的 p 从 0.0625 推到了 0.094 再到 0.219。 每一次修正都是向着 预注册规格靠近,不是向着好看靠近。方向一次都没变:主检验均值差在全部 18 个 「修正版本 × 密度」组合里全部为正;清醒态正向超出在双角色节点集下于 5/6 个密度为正、 3 个密度上 6/6 被试同号。
判决不变,且比之前更清楚地是「功效不足」:n=6 时六人同号的双侧 p 天花板就是 0.031, 主检验只在 2/6 个密度上碰到这个天花板。方向稳定、显著性随密度跳动、 一个被试(PRIOS03,双角色节点仅 20 个)的噪声足以翻转主检验—— 这就是样本量不够的标准长相。
这轮修正最有价值的产出不是 p 值,而是:原报告 §6.4「麻醉态显著地比随机图更不递归」 这一「发现」被证实是缺陷产物,撤回。修正后麻醉态在任何密度下都与零无法区分。
PRIOS完整方法学与结果报告.md §4.1 写的是节点 = 双角色电极
(既被刺激过又被记录的电极)。代码实现用的是全部共同通道。
如果按文档办(节点集收缩成双角色电极),源占比恒等于 1,本缺陷自动消失。 如果按代码办,就需要 §5 的修正。
这两条路都成立,但必须选一条,并让文档和实现一致。 我倾向按 §5 修零模型而不是收缩节点集,因为被刺激电极之外的记录电极 承载了真实的接收端信息,删掉它们会丢数据; 但这一条应该由你或元宝那边定,因为它触及预注册的措辞。
不是靠复查代码发现的,是在找数据时顺带发现的:
一个并行的检索任务在核对数据格式时读了 prios_分析.py,
注意到 srcs 和 prs 两处对「谁能发边」的约定不一致。
教训:这个缺陷在所有既有闸门下都是隐形的。
闸门①(阴性对照)、闸门③(距离)、闸门⑤(CE 饱和阈值)、
ce_mass 判别力标定——没有一个会触发,因为它们检验的都是
「检出的边是不是真的」,没有一个检验
「零模型和观测图是不是在同一个约束下生成的」。
建议新增一条通用闸门:任何置换零模型,都要先问一句 「观测图不可能出现的边,零模型会不会产生?」 如果会,零模型就比观测图更自由,差值里混进了纯结构性的偏移。 廉价的验法就是 §3 那个——把真实结构全部抹掉,看零模型还能不能造出差异。