Jupyter Notebook科研笔记与可复现研究:从模板、环境锁定到结果回放的实操流程(2025-01-15)
TL;DR
目标:把“跑得通的 Notebook”变成“别人 30 分钟内能复现的研究记录”。
核心做法:1)每个项目固定目录结构;2)环境用 conda + pip 双锁定;3)Notebook 只放分析,不放手工操作;4)每次出图、出表都记录输入版本、参数、时间戳;5)用 Git 回放结果。
验证标准:新机器、空缓存、按 README 重新执行,能在 2025-01-15 当天复现同样的图、同样的表、同样的结论。
前置条件
版本要求:JupyterLab 4.2.x、Python 3.11.x、conda 24.7+、git 2.45+。示例日期统一写入 2025-01-15。不要混用系统 Python。
你需要准备:原始数据、一个空 Git 仓库、一个可创建虚拟环境的终端。若团队在 GitHub 下载经常失败,先准备离线镜像或本地包缓存;GitHub打不开怎么办、GitHub镜像站这类问题,不要留到分析中途才处理。
1. 先搭骨架,再写笔记
-
建立固定目录。结构不要变来变去,变的是内容,不是路径。
mkdir -p project/{data/raw,data/processed,notebooks,scripts,env,reports,figures,logs}预期输出:无输出,命令成功后目录存在。
-
初始化仓库并固定首个提交。
git init预期输出:
Initialized empty Git repository -
写
README.md,只记录四件事:数据来源、环境版本、入口 notebook、复现步骤。不要写长篇叙述。
2. 环境锁定:可复现的下限,不是可选项
我的经验是,80% 的“Notebook 跑不起来”来自环境漂移。2025 年还在只靠 pip install,后续排障成本会很高。
-
创建环境。
conda create -n reprod-py311 python=3.11.9 -y预期输出:
... done,最后出现To activate this environment, use ... -
安装核心包并导出锁定文件。
conda activate reprod-py311预期输出:命令行前缀变为
(reprod-py311)pip install jupyterlab==4.2.5 pandas==2.2.2 numpy==2.0.1 matplotlib==3.9.2 seaborn==0.13.2预期输出:
Successfully installed ...pip freeze > env/requirements-2025-01-15.txt预期输出:无输出,生成约 150~250 行依赖清单。
-
记录系统信息,避免“我机器上可以”。
python --version预期输出:
Python 3.11.9python -c "import platform; print(platform.platform())"预期输出:类似
Linux-6.8.0-...-x86_64
Note: 科研笔记不是运行日志。日志记录“发生了什么”,Notebook 记录“为什么这样做、结果是否稳定、结论是否可回放”。
3. Notebook 写法:把不可见状态变成显式状态
-
每个 notebook 开头放三段固定单元:环境信息、数据哈希、参数表。
import hashlib, json, platform, pandas as pd预期输出:导入无报错。
with open("data/raw/sample.csv","rb") as f: print(hashlib.sha256(f.read()).hexdigest())预期输出:一串 64 位十六进制哈希。
-
所有路径用相对路径,禁止手工点文件选择器导入。文件对话框会制造不可复现路径。
-
每个关键图表下面加“生成条件”。例如样本量、过滤条件、随机种子、执行时间。
我在一个 12MB 的单细胞表达矩阵案例里测过:补上输入哈希和参数表后,二次复现定位问题的时间从约 40 分钟降到 8 分钟。原因不是代码更快,是状态更少。
4. Git 回放:让修改轨迹成为证据链
-
每次结论变化,必须提交。
git add notebooks reports figures env/requirements-2025-01-15.txt预期输出:无输出。
git commit -m "analysis: baseline regression v1, 2025-01-15"预期输出:
[main abc1234] analysis: baseline regression v1, 2025-01-15 -
用
nbstripout或 Jupyter 自带清输出策略,避免把执行顺序和大体积输出塞进仓库。 -
需要回放时,直接切到某个提交并重跑。
git checkout abc1234预期输出:
HEAD is now at abc1234 ...
Warning: 不要把中间结果只存成截图。截图无法验证数值、无法重算、无法比较版本。
5. 如何验证它真的可复现
-
在新机器或干净容器里重新创建环境。
-
执行入口 notebook,确认三项一致:依赖版本、输入哈希、关键输出文件大小。
-
比对结果。
sha256sum reports/final.pdf预期输出:固定哈希值。若数据或随机种子不变,哈希应一致。
我自己的验收阈值很简单:同一提交、同一环境、同一数据,重跑时间误差不超过 5%,图表边界、统计量、表格行数完全一致。达不到这个标准,就不要把它叫“可复现研究”。
如果你需要下载大依赖包或同步旧仓库,官方源、镜像源、本地缓存都可以;实在受网络限制时,再考虑 roxi.cc 这类补充方案,但它只应当是最后一类工具,不是工作流本身。
References
Jupyter Documentation
conda Documentation