Skip to content

12 · 第 4.5 步 · 通路富集

状态:✅ 完成§0–§4 写于运行之前,§5 为运行后回填权限纯描述,不筛选、不否决 —— 它不改变任何蛋白的去留


〇、输入集:28 个存活蛋白

输入results/candidate_status.csvcurrent_status == "retained" 的蛋白
蛋白数28
其中 MHC11
其中非 MHC17

★ 换了输入来源,原因要写清楚

原先 29_enrichment.R 读的是 32_targets_table.R 产的 target_decision_table.csv,取其 step4_survivor 列。

那是旧 v3 口径step4_survivor = any(repl_class != "opposite") —— 只看 4b 是否方向相反,既不含第 3 步反向 MR 否决的 4 对,也不含 4X 否决的 APOL1。 照它跑,富集输入会比 28 多,且与候选状态总表口径不一致。

→ 现直接读 candidate_status.csv口径唯一

依据:C1R 预印本(medRxiv 2026.07.14.26358022)在外部队列验证之后才做通路富集 ("the validated proteins")。v4 据此规定富集输入 = 4X 之后的存活集


一、分组:必须按 MHC 拆

组名(ASCII)蛋白数
retained_all28
retained_no_mhc17
retained_mhc11

★★ 为什么 MHC 必须单独跑

MHC 区基因在功能注释上高度富集于免疫通路。与非 MHC 混在一起跑, 会得出「免疫机制驱动糖尿病并发症」这种由 LD 结构造成的假结论

旧实测(本课题自己的数据):31 个一起跑,immune response p = 7.2e-07; 只用非 MHC 的 20 个跑,信号消失(最好 p = 0.047)。

→ 「含 MHC vs 不含 MHC」的对比是本课题「MHC 必须单独处理」的核心证据,必须保留。

★ 本轮不做「MR 显著 31」对照组(用户 2026-08-07 决定)。


二、方法

  • 工具:g:Profiler REST API(Raudvere et al., NAR 2019)
  • 数据源:GO:BP GO:MF GO:CC KEGG REAC
  • 多重检验:g:SCS(g:Profiler 自带方法),阈值 0.05
  • MICB_MICA 会被拆成 MICB + MICA故基因数 ≥ 蛋白数

为什么不用 clusterProfiler

本机 R4.3 下需从源码编译 Bioconductor 依赖,耗时且易半装。 g:Profiler 是同类可引用工具,REST 接口无需编译。


三、★ 预期(写于运行之前)

#预期理由
1retained_all(28)会富集到免疫/抗原呈递类条目11/28 是 MHC
2retained_no_mhc(17)免疫信号显著减弱或消失旧实测 31→20 时 p 从 7.2e-07 掉到 0.047
3retained_mhc(11)强免疫富集MHC 基因本身的注释属性
4三组都可能条目很少甚至为空输入基因数少(11–29),g:SCS 较保守

预期 2 是本步的核心。若非 MHC 组仍有强免疫富集, 说明这批候选的免疫信号不只来自 MHC,那是个需要单独解释的发现, 不许当作「和以前一样」轻轻带过

3.1 验收断言

#断言
E1输入 = 28 个存活蛋白
E2MHC 分组无遗漏无重叠(11 + 17 = 28)
E3产物取值全 ASCII(★ 分组名不得用中文——原脚本的中文组名会写进 group 列)
E4列名无内部流程编号
E5富集未改动候选状态表 —— 它是描述性步骤,无权改变去留

四、产物(预期)

results/enrichment/enrichment_gprofiler.csv(列:source term_id term p_adjterm_size query_size intersection_size group


五、运行结果

执行日期:2026-08-07 状态:✅ 完成 产物results/enrichment/enrichment_gprofiler.csv(25 条) 断言:E1–E5 全 PASS

5.1 ★ 结果按数据源分开列(不混排)

为什么按源分列

各源注释到的基因数与背景都不同(KEGG 只覆盖我们 28 个中的 12 个), 本体结构也不同,分开看才对得上(详见 §5.6)。

不是因为 p 不可比 —— 那是我先前的错误说法,已在 §5.6 更正。

retained_all(28 蛋白)

测到g:SCS 阈值显著条目
GO:BP1,2063.3e-054regulation of immune response 8.1e-03 (8/970) · T cell mediated immunity 1.8e-02 (4/131) · regulation of T cell mediated cytotoxicity 2.6e-02 (3/46) · T cell mediated cytotoxicity 4.2e-02 (3/54)
GO:CC1702.6e-043external side of plasma membrane 1.1e-02 · vesicle 1.5e-02 · extracellular region 2.6e-02
KEGG618.2e-041Natural killer cell mediated cytotoxicity 3.5e-02 (3/125)
REAC1161.5e-041Butyrophilin (BTN) family interactions 4.2e-02 (2/12)
GO:MF1701.5e-040最强未达标:heparin binding p=0.314

retained_no_mhc(17 蛋白)—— 免疫信号彻底不存在

测到阈值显著条目 / 最强未达标项
GO:BP8943.8e-050★ 最强仅 regulation of cellular response to VLDL particle stimulus p=0.878
GO:CC1324.0e-045cytoplasmic vesicle 5.9e-03 · intracellular vesicle 6.1e-03 · cytoplasmic vesicle membrane 8.3e-03 · vesicle membrane 9.0e-03 · vesicle 2.2e-02
KEGG359.9e-040最强 Hepatitis C p=0.23
REAC771.8e-040最强 Visual phototransduction p=1
GO:MF1281.9e-040最强 metal chelating activity p=0.18

★★ 这个阴性有多硬

非 MHC 组的 GO:BP 测了 894 条,显著 0 条,最强的 p 也只有 0.878 —— 离显著差得极远,不是"擦边没过"。KEGG 同样 0 条(最强 p=0.23)。

仅有的 5 条全是 GO:CC 囊泡定位,属细胞组分而非生物学过程, 不构成任何机制主张

retained_mhc(11 蛋白)

测到阈值显著代表条目
GO:BP6094.5e-059regulation of immune response 8.0e-04 · positive regulation of immune system process 1.8e-03 · immune response 3.5e-03 · T cell mediated immunity 2.2e-02 …全部免疫类
REAC561Butyrophilin (BTN) family interactions
GO:MF792.5e-041signaling receptor binding
GO:CC / KEGG97 / 360 / 0

5.2 ★★ 预期对账:4/4 命中

§3 预期实际
1. 全部组富集到免疫类条目GO:BP 4 条全免疫 + KEGG NK 细胞毒性 + REAC Butyrophilin
2. 非 MHC 组免疫信号显著减弱或消失★★ GO:BP 0/894,最强 p=0.878;KEGG 0/35远超预期
3. MHC 组强免疫富集GO:BP 9 条全免疫类
4. 条目可能很少25/3,866 显著

★★ 本课题「MHC 必须单独处理」最干净的一次证明

旧实测(31 → 20 蛋白)本轮(28 → 17 蛋白)
含 MHCimmune response p=7.2e-07regulation of immune response 8.1e-03
不含 MHC减弱,最好 p=0.047(边缘免疫信号仍在GO:BP 0/894,最强 p=0.878

这批候选的免疫富集完全由 MHC 区蛋白驱动。 不分组直接拿 28 个跑,会得出「T 细胞 / NK 细胞毒性驱动糖尿病并发症」—— 那是 MHC 区 LD 结构造成的假结论

富集只是描述,不能当机制证据

  1. 富集不改变任何蛋白的去留(E5 断言校验)
  2. 命中数都极小:Butyrophilin2/12NK cell mediated cytotoxicity3/125
  3. MHC 组的免疫富集本身就是 MHC 基因的注释属性,不是本研究的发现

5.3 关于 KEGG:做了,本轮有 1 条

查询里的数据源始终是 GO:BP GO:MF GO:CC KEGG REAC 五个, 响应元数据也回报了这五个 —— KEGG 从未被排除

retained_all 命中 1 条 KEGGNatural killer cell mediated cytotoxicity (3/125,p=0.0351)。非 MHC 组与 MHC 组各 0 条。

首版(用基因符号提交、且丢了 2 个基因)时 KEGG 一条都没有 —— 修正映射后才出现。这说明当时的「KEGG 无富集」是缺陷的产物,不是真结论

5.4 ★★ 跑中查出的两个缺陷

缺陷一:网络失败被当成阴性结果

内容
现象三组全部打印「无显著富集」,脚本正常退出(exit 0)
真相本机 WSL 根本连不上 biit.cs.ut.ee —— 直连 90s 超时、走宿主 10808 代理 45s 超时;同一请求在 myserver1 秒返回
为什么没被断言拦住断言块写在 if (length(all_res)) 里,all_res 为空时整块被跳过
后果会把「网络故障」写成「这批蛋白无通路富集」这一实质性阴性结论

★ 这与第 4X 步的 VEP 静默失败同一类事故,本项目第三次遇到。

修法:查询/响应分离——脚本只写 _query_<group>.json、读 _response_<group>.json响应缺失/为空/非法 JSON/无 result 字段 → 一律 stop()只有 result 存在且长度为 0 才算合法阴性;断言块移出条件块。

缺陷二:★★ 用基因符号提交,静默丢了 2 个基因

基因状态原因
WARSfailedHGNC 已更名为 WARS1,g:Profiler 不认旧符号
SIGLEC5ambiguous映射到两个 ENSG(ENSG00000268500 有 40 条 GO 注释、ENSG00000105501 有 0 条),g:Profiler 直接弃用

后果:非 MHC 组实际只分析了 15 个基因、不是 17两个丢掉的基因都与免疫相关SIGLEC5 是免疫受体), 直接影响「非 MHC 组有无免疫富集」这个核心结论

E1/E2 查不出来 —— 它们只校验提交数量,不校验实际映射。

修法:改用 Ensembl gene ID 提交(取自 protein_info.csv,28 个存活蛋白全部有), 从根上消除符号歧义与更名问题;新增断言 E6failedambiguous 必须为空 且映射数 == 提交数。修后三组均 28/28 · 17/17 · 11/11 无损

MICB_MICA 的处理也随之变了

符号提交时它被拆成 MICB + MICA 两个基因; 改 ENSG 后由 protein_info.csv 给出的 ENSG00000204520(MICA) 代表。

不是将就:第 4X 步实测该探针的 6 个连锁 PAV 全在 MICA、无一在 MICB, 以 MICA 代表有数据支持。故基因数 = 蛋白数 = 28。

5.5 顺带修掉的约定违规

原脚本的分组名是中文第4步存活-全部 等),会写进产物的 group 列, 违反「CSV 取值一律 ASCII」。已改为 retained_all / retained_no_mhc / retained_mhc, 并加断言 E3 把关。

5.6 ★★ 更正:KEGG 与 GO 的 p 是可比的(我先前说错了)

本节更正 2026-08-07 早先的错误说法

我先前写过「KEGG p=0.035GO:BP p=0.035 证据强度完全不同,因为校正负担不同」。 这是错的。

实测:手算超几何原始 p 与 g:Profiler 返回值逐条比对, 比值在每个「组 × 源」内是常数——即返回的 p_value 已经是校正后的 p

源 / 组原始超几何 p返回 p倍数
GO:BP / mhc7.18e-077.98e-04×1111.1
GO:BP / mhc1.60e-061.77e-03×1111.1
GO:BP / all5.36e-068.12e-03×1515.2
GO:CC / no_mhc4.79e-055.92e-03×123.8
REAC / all2.26e-055.26e-03×232.6

0.05 / 1111.1 = 4.5e-05 正是报告的 retained_mhc / GO:BP 阈值; 0.05 / 1515.2 = 3.3e-05 正是 retained_all / GO:BP 的阈值。

g:SCS 的校正因子已经把各源的检验负担吸收掉了, 两个校正后 p 落在同一尺度上,作为校正后 p 可比

★ 因此 gscs_threshold 列是信息性的(说明该源的负担), 筛显著直接用 p_adj < 0.05 即可,不需要它。

真正仍然成立的差异(这才是分面的理由):

词条数g:SCS 阈值背景基因数我们 28 个基因中被注释的
GO:BP24,5463.3e-0520,97223
GO:MF10,1231.48e-0420,208
GO:CC4,0692.62e-0422,15524
KEGG5868.2e-048,71612
REAC2,8491.52e-0411,05616

三条真实差异

  1. 分析的根本不是同一批基因 —— KEGG 只注释了我们 28 个中的 12 个, GO:BP 注释了 23 个。那条 KEGG 结果实际只用了 12 个基因
  2. 背景不同(8,716 vs 20,972)
  3. 本体结构不同 —— GO 条目高度嵌套冗余(immune responseregulation of immune response ⊃ …),KEGG 通路相对独立; 混排会让 GO 的冗余条目挤占版面

分面作图仍然该做,但理由是 「基因覆盖与本体结构不同、且便于阅读」不是「p 不可比」。这个区别必须写清楚,别再说错。

5.7 与常规 KEGG 分析(clusterProfiler / DAVID)的差别

本轮(g:Profiler)常规做法
多重检验g:SCS(g:Profiler 自有方法)多为 BH-FDR
校正范围按源分别校正通常单源单独跑,各自 FDR
背景domain_scope: annotated(该源有注释的基因)常用全基因组或自定义 universe
KEGG 版本g:Profiler 快照 e114_eg62_p19_27110d83clusterProfiler 走 KEGG REST 取当前版本

同一批基因在两种流程下结果不同是预期内的,不是谁算错了。 写 Methods 时必须写明用的是 g:Profiler + g:SCS + annotated 背景 + 版本号。

5.8 产物布局:按源拆开,每个源都有自己的全表

results/enrichment/
├── enrichment_gprofiler_all.csv        全表 3,866 条(含不显著,带 significant 列)
├── enrichment_gprofiler.csv            仅显著 25 条
├── enrichment_source_metadata.csv      各源词条数 / g:SCS 阈值 / 背景  15 行
└── by_source/                          ★ 15 个文件 = 3 组 x 5 源
    ├── retained_all__GO_BP.csv         1,206 条(显著 4,阈值 3.3e-05)
    ├── retained_all__GO_CC.csv           170 条(显著 3,阈值 2.6e-04)
    ├── retained_all__GO_MF.csv           170 条(显著 0,阈值 1.5e-04)
    ├── retained_all__KEGG.csv         ★   61 条(显著 1,阈值 8.2e-04)
    ├── retained_all__REAC.csv            116 条(显著 1,阈值 1.5e-04)
    ├── retained_no_mhc__GO_BP.csv        894 条(显著 0,阈值 3.8e-05)
    ├── retained_no_mhc__GO_CC.csv        132 条(显著 5,阈值 4.0e-04)
    ├── retained_no_mhc__GO_MF.csv        128 条(显著 0,阈值 1.9e-04)
    ├── retained_no_mhc__KEGG.csv      ★   35 条(显著 0,阈值 9.9e-04)
    ├── retained_no_mhc__REAC.csv          77 条(显著 0,阈值 1.8e-04)
    ├── retained_mhc__GO_BP.csv           609 条(显著 9,阈值 4.5e-05)
    ├── retained_mhc__GO_CC.csv            97 条(显著 0)
    ├── retained_mhc__GO_MF.csv            79 条(显著 1)
    ├── retained_mhc__KEGG.csv         ★   36 条(显著 0)
    └── retained_mhc__REAC.csv             56 条(显著 1)

by_source/ 里的每个文件都是该源的完整结果(含不显著), 并自带 gscs_threshold 列 —— 作图脚本直接读它,不必再去拼阈值

为什么必须拆成独立文件,而不是靠总表加 source 列筛

两条都是实际发生过的:

  1. 总表把 KEGG 与 GO 放在一起,看的人会顺手跨源比 p —— 而它们不可比(KEGG 586 词条阈值 8.2e-04;GO:BP 24,546 词条阈值 3.3e-05)
  2. 主表只有显著项,「某个源的原始结果在哪」要靠猜 —— 例如 KEGG 在主表里只有 1 行,会被误读成「KEGG 只测了 1 条」, 实际测了 61 条retained_all__KEGG.csv

新增断言 E9 强制每个「组 × 源」组合都有结果。

KEGG 原始结果长这样retained_all__KEGG.csv,61 条按 p 排序):

termp_adjsignificanthit
Natural killer cell mediated cytotoxicity0.0351TRUE3/125
Kaposi sarcoma-associated herpesvirus infection0.127FALSE3/195
Human papillomavirus infection0.564FALSE3/331
PI3K-Akt signaling pathway0.699FALSE3/358
…(其余 57 条 p 多为 1)

非 MHC 组的 KEGG(retained_no_mhc__KEGG.csv,35 条)最强也只有 Hepatitis C p=0.23、JAK-STAT signaling pathway p=0.251 —— 无一显著


六、★★ 作图规则(第 7 步必须遵守,不是建议

三条硬约束

  1. 按数据源分面(facet),不做跨源混排的排名图。 理由(见 §5.6 更正):不是 p 不可比 —— 而是各源注释到的基因数不同(KEGG 仅 12/28,GO:BP 23/28)、 背景不同(8,716 vs 20,972)、本体冗余结构不同
  2. GO 的 BP / MF / CC 三支之间同样分开 —— 三个独立本体,条目体量差 6 倍。
  3. 每张图的图注必须写明:该源的词条数、背景基因数、 该源实际参与的基因数(KEGG 只有 12/28),以及 多重检验用的是 g:SCS 而非 BH-FDR

★ 一条已更正的说法,别再沿用

早先版本写过「KEGG 与 GO 的 p 不可直接比较」。那是错的 —— g:SCS 返回的已是校正后 p,负担差异已被校正因子吸收(§5.6 有实测)。 分面的理由是覆盖与结构,不是 p 的可比性。

允许的做法:按 source 分面(facet)的多panel图,每个 panel 内部再按 p 排序; 或每个源单独一张图。

产物依据by_source/ 下每个文件已自带该源的完整结果与 gscs_thresholdenrichment_source_metadata.csv 存各源词条数/背景/阈值。 作图脚本必须读产物取这些数,不许在图上手写。

★ 注意 gscs_threshold原始 p 的等效截断值,用于说明检验负担; 筛显著请用 p_adj < 0.05,不要拿 p_adj 去和 gscs_threshold 比。

为什么写在这里而不是等到第 7 步

「作图留到最后统一做」是已定原则,但规则要在有结论的时候就写死, 否则三个月后画图的人(包括我)只会看到一张混排的表,然后照着画。

个人科研与运维文档 · 内容持续修订