Workflow / Reproducibility

Python 与可复现研究工作流

把研究项目看成一个可复跑的有向无环图,而不是一组手工文件。

Mechanism Lab

动画:研究产出如何沿 DAG 流动

动画中的信号从 raw data 出发,经过 clean、feature、model、table,每一步都留下可验证文件。

Step 1 / 5

Raw

原始数据只读保存。

D0

Animation Control

Reduced-motion users receive the same step states without continuous motion.

01 / 直觉

核心直觉

可复现研究的核心不是“会写 Python”,而是让数据、代码、参数、输出之间的依赖关系可以被检查。

一个结果表不是一个孤立文件,而是函数 F(raw data, code, config, seed) 的输出。

当依赖图清楚时,人类、审稿人和 Agent 都能复跑、定位错误、替换数据并比较差异。

02 / 数学

把研究流程写成依赖图

01 / 状态定义

令 D0 表示原始数据,C 表示代码,theta 表示配置,s 表示随机种子。任何可复现输出都应能写成确定性映射。

Y = F(D0, C, theta, s)

02 / DAG 约束

若节点 v_j 依赖 v_i,则必须先生成 v_i。拓扑排序给出可复跑顺序。

v_i -> v_j  implies  order(v_i) < order(v_j)

03 / 审计条件

输出变化 Delta Y 必须能分解到数据、代码或配置变化,而不是不可见的手工编辑。

Delta Y = F(D0, C2, theta, s) - F(D0, C1, theta, s)

03 / 代码

最小 pipeline 代码

下面的例子把清洗和分析分成两个函数,并显式记录输入输出。

from pathlib import Path
import pandas as pd

ROOT = Path("project")

def clean(raw_path: Path, out_path: Path) -> pd.DataFrame:
    df = pd.read_csv(raw_path)
    df = df.drop_duplicates("id")
    df["post"] = (df["year"] >= 2020).astype(int)
    df.to_parquet(out_path, index=False)
    return df

def summarize(clean_path: Path, table_path: Path) -> None:
    df = pd.read_parquet(clean_path)
    table = df.groupby("post")["outcome"].agg(["count", "mean", "std"])
    table.to_csv(table_path)

clean(ROOT / "data/raw.csv", ROOT / "data/processed.parquet")
summarize(ROOT / "data/processed.parquet", ROOT / "tables/descriptive.csv")

04 / 案例

案例:把 Excel 工作流改成可审计 pipeline

  • 把一份手工 Excel 研究流程拆成 raw data、clean script、analysis script 和 outputs。
  • 每个输出表格都能追溯到输入数据、代码版本和随机种子。
  • Agent 只能在这种结构上可靠工作;否则它只能猜测文件含义。

05 / 风险

常见误区

只保存 notebook 而没有运行顺序。
输出表格被手工改过但没有留下 provenance。
路径、随机种子和依赖版本没有固定。

参考资料