研究问题、可复现分析与敏感性分析03 / 16
可复算的分析
两个概念
可复算(reproducible):用相同的数据、相同的代码和步骤,得到相同的结果。可重复(replicable):用新的数据、按相同的方法,得到一致的结论。任何计算分析至少要做到可复算;有条件时,用第二个数据集或子样本检验可重复性。
可复算看似是最低要求,实际上并不容易达到。Stodden 等(2018)随机抽取 Science 在 2011 年实行数据与代码政策后发表的 204 篇计算类论文,向作者索取材料:只拿到了其中 44% 的数据和代码,能复现结果的为 26%。Trisovic 等(2022)在干净环境中重新运行 Harvard Dataverse 上 2000 多个复现数据包中的 9000 多个 R 脚本,74% 的文件初次运行即报错,经自动清理代码后仍有 56% 报错。这些数字说明:“代码已共享”不等于“结果可复算”。
Sandve 等的十条规则
Sandve 等(2013)的十条规则至今仍是计算可复算性的基本框架。下面按其要点给出网络分析中的对应做法:
| 规则要点 | 网络分析中的做法 |
|---|---|
| 1. 记录每个结果是怎样产生的 | 每张图、每个数值都能追溯到一个脚本和一组参数 |
| 2. 避免手工处理数据 | 不在 Excel 里手改基因名;ID 映射写成代码并保存映射表 |
| 3. 存档所用外部程序的确切版本 | 记录 networkx、igraph、bctpy、bootnet 等的版本;数据库同样要记版本 |
| 4. 对自己的脚本做版本控制 | 用 Git,每个结果对应一个提交号 |
| 5. 尽量用标准格式保存中间结果 | 保存邻接矩阵、边列表(如
.npz、.csv、GraphML),而不只保存最终图 |
| 6. 有随机性的分析要记录随机种子 | Louvain、bootstrap、度保持随机化都要记录种子(见随机性控制) |
| 7. 保存图背后的原始数值 | 每张敏感性曲线都保存对应的数值表 |
| 8. 输出分层次的结果 | 汇总表 → 每个参数组合的结果 → 单次运行的日志 |
| 9. 把文中陈述与具体结果对应起来 | 正文中的每个数值都能在结果文件中找到 |
| 10. 公开脚本、运行记录和结果 | 见数据与代码共享 |
七条日常做法
- 原始数据只读:下载的原始文件不手工修改,所有清洗步骤写在代码里。
- 记录数据版本:数据库名称、版本号和下载日期写进 README,例如“STRING v12.0,2026-11-10 下载,人类 9606,综合置信度 ≥ 700”。数据库会更新,不记版本就无法复算。
- 用脚本,不用鼠标:Cytoscape、Gephi 适合可视化和探索,但关键数值结果应由脚本生成。确需手工操作时,逐步写进实验记录。
- 固定随机种子:Louvain、随机网络、bootstrap、置换检验都有随机性。固定种子是为了可复算;报告结论时则要跑多个种子,说明结论不依赖于某一个种子(见敏感性分析与替代解释)。
- 记录环境:
requirements.txt或environment.yml写明 Python/R 和关键包版本(例如 networkx 3.x 的 Louvain 实现与旧版不同),详见计算环境与工作流。 - 版本控制:用 Git 管理代码和文档,每完成一步就提交一次,提交说明写清“做了什么”。
- 一键重跑:最终发布前,从原始数据出发运行一遍完整流程,确认所有图表都能重新生成。
推荐的项目目录(与 The Turing Way 所说的“研究纲要”(research compendium)思路一致):
project/
├── README.md # 问题、数据来源与版本、运行方法
├── LICENSE # 代码许可;数据另行说明
├── environment.yml # 或 requirements.txt + 锁定文件
├── data/raw/ # 原始数据(只读,不提交大文件,写明下载方式)
├── data/processed/ # 由代码生成
├── code/ # 01_clean.py, 02_build_network.py, 03_analysis.py ...
├── results/ # 图表与数值结果,由代码生成
└── report/ # 报告与幻灯片
溯源记录
溯源(provenance)指每个结果从哪些输入、经过哪些步骤、在什么环境下得到。最轻量的做法是每次运行时自动写一个“运行清单”:软件版本、参数、随机种子,以及输入与输出文件的 SHA-256 哈希。哈希相同说明文件逐字节相同;换机器后输出哈希改变,就可以按清单逐项排查是数据、参数还是软件版本变了(见本专题代码示例“运行清单”)。