3. 分析项目目录结构设计

在组学数据分析中,目录结构往往是最容易被忽视、却对可复现性影响最大的基础设施之一。一个项目在三个月后能否被自己或他人重新跑通,很大程度上取决于原始数据是否被保护、衍生数据是否可追溯、脚本与结果是否一一对应。本节讨论的不是“把文件放整齐”这种审美问题,而是如何用目录结构承载数据血缘、运行边界和复现契约。

为什么目录结构是可复现性的一部分

组学项目通常包含多来源、多阶段、多版本的数据:测序下机的 FASTQ、质控后的 clean reads、比对得到的 BAM、定量得到的 count 矩阵、差异分析结果表、富集分析结果以及最终图表。如果这些文件混放在同一目录,并用 result_final.csv、result_final2.csv 这类名称区分,那么复现时无法判断哪个文件对应哪次运行、用了哪版参考基因组、由哪个脚本产生。目录结构的作用,是把“数据从哪来、经过什么处理、产生什么结果”编码进路径本身,使路径成为可读的血缘线索。

因此,目录规范要解决三个核心问题:原始数据只读且不可变、衍生数据可重建且可追溯、代码、配置与结果相互对应。围绕这三点,可以设计一套稳定、可迁移的项目骨架。

推荐的项目目录骨架

下面给出一个适用于典型 RNA-seq / 变异检测类项目的目录结构示例。它并非唯一正确方案,但体现了原始与衍生分离、按阶段分层、代码与数据解耦的原则。

project_root/
├── README.md                 # 项目说明、运行入口、环境要求
├── config/
│   ├── samples.tsv           # 样本表:sample_id、fq1、fq2、group
│   ├── params.yaml           # 分析参数:参考基因组版本、线程数、阈值
│   └── env/
│       ├── environment.yml   # conda 环境导出
│       └── versions.txt      # 关键工具版本锁定
├── data/
│   ├── raw/                  # 原始数据,只读,禁止修改
│   │   ├── fastq/
│   │   └── metadata/
│   ├── interim/              # 中间数据,可删除可重建
│   │   ├── qc/
│   │   ├── trimmed/
│   │   └── aligned/
│   └── processed/            # 最终衍生数据,供下游与共享
│       ├── counts/
│       └── variants/
├── scripts/
│   ├── 01_qc.sh
│   ├── 02_align.sh
│   ├── 03_quantify.R
│   └── utils/
├── results/
│   ├── tables/
│   ├── figures/
│   └── logs/
└── docs/
    └── analysis_notes.md

其中 data/raw/ 是项目的“事实来源”,任何脚本都只读不写;data/interim/ 存放可重建的中间产物,允许清理;data/processed/ 存放经过确认、准备用于下游分析或共享的衍生数据;results/ 存放图表与日志,与数据分离,避免结果文件污染数据目录。

组学项目目录结构与数据流向 data/raw/(只读) fastq/ 下机数据 metadata/ 样本信息 禁止修改 · 校验和记录 md5: a3f1…c9e2 data/interim/(可重建) qc/ · trimmed/ aligned/ · sorted.bam 可删除 · 由脚本重建 依赖 config/params.yaml data/processed/ counts/ 表达矩阵 variants/ 变异结果 稳定 · 供下游与共享 版本化命名 01_qc 02_align 03_quantify 04_call config/ samples.tsv params.yaml env/ 环境锁定 scripts/ 01_qc.sh 02_align.sh 03_quantify.R results/ tables/ 结果表 figures/ 图表 logs/ 运行日志 参数注入 输出 复现契约:raw 只读 → 脚本 + config 重建 interim → 确认后固化为 processed → 结果与日志独立存放 路径即血缘:任何衍生文件都能沿目录与命名回溯到原始数据和处理参数

命名约定:让文件名携带元信息

目录分层之后,命名约定决定同一层内文件能否被机器和人都正确识别。推荐采用“实体—阶段—版本—扩展名”的可解析命名,字段之间用下划线或短横线统一分隔,避免空格和中文。例如:

# 样本表 config/samples.tsv
sample_id   fq1                         fq2                         group
S01         data/raw/fastq/S01_R1.fq.gz data/raw/fastq/S01_R2.fq.gz control
S02         data/raw/fastq/S02_R1.fq.gz data/raw/fastq/S02_R2.fq.gz treated

# 衍生文件命名示例
data/interim/aligned/S01.sorted.bam
data/processed/counts/rnaseq_counts_v1.tsv
results/tables/deseq2_S01-S02_vs_control_v1.csv
results/figures/pca_counts_v1.pdf

命名中应避免 final、new、test 这类无信息词。版本号建议用 v1、v2 或日期 20250601,并在 docs/analysis_notes.md 中记录每次版本变更的原因。对于参考基因组、注释版本等关键依赖,应写入文件名或参数文件,例如 GRCh38.p14,而不是只记在某人脑中。

原始数据与衍生数据的分离原则

原始数据与衍生数据分离,不只是分目录,而是要在权限、校验和写入策略上落实。具体做法包括:

  • 权限只读:对 data/raw/ 设置只读权限,脚本中不出现写入该目录的命令。若使用 Linux,可用 chmod -R a-w data/raw 防止误写。
  • 校验和登记:下机后立即对 FASTQ 计算 md5 或 sha256,写入 data/raw/metadata/checksums.md5,后续任何分析前先校验,确保输入未被篡改。
  • 衍生数据可重建:data/interim/ 中的文件应能由 scripts/ 加 config/ 重新生成。若删除该目录后无法重建,说明脚本或参数记录不完整。
  • processed 与 results 分离:data/processed/ 存放数据矩阵、变异表等“数据型”产物;results/ 存放统计表、图表、日志等“报告型”产物。两者混放会导致共享时把中间数据误当最终结果。
一个实用的自检方法:把项目复制到另一台机器,只保留 data/raw/、config/、scripts/,然后按 README 运行。如果 data/processed/ 和 results/ 能被完整重建,说明目录结构达到了可复现要求。

落地检查清单

在项目启动时,可以用下面这份清单快速核对目录设计是否到位。它不追求形式完整,而是覆盖最容易导致复现失败的关键点。

检查项合格标准常见问题
原始数据保护raw 只读,有校验和文件直接在下机目录上跑分析并覆盖
样本表完整性samples.tsv 含 sample_id、fq1、fq2、group样本信息散落在脚本注释中
参数集中管理参考版本、线程、阈值写入 params.yaml参数硬编码在命令行历史里
脚本可重入重复运行不破坏已有结果,输出路径固定每次运行生成新目录,无法对应
衍生数据可重建删除 interim 后能由脚本重建中间文件靠手工拖拽生成
结果可追溯图表文件名含分析类型与版本figure1.pdf、result.csv 无信息

目录结构设计不是一次性的整理动作,而是项目运行过程中持续维护的契约。当分析阶段增加、样本规模扩大或需要共享给合作者时,稳定的目录规范和命名约定会显著降低沟通成本,也让“可复现”从口号变成可执行的工程习惯。