跳转至

855. 生信可重复性指南

一句话概述:可重复性 = 别人拿到你的代码和数据,能得到完全一样的结果——这是科学的基石,也是生信工程师的专业素养体现。

核心知识点速查表

层面工具/方法目的
代码版本Git追踪代码变更历史
数据版本DVC追踪大文件版本
软件环境Conda/Docker锁定软件版本
流程管理Snakemake/Nextflow自动化分析流程
文档记录README + Jupyter记录分析步骤
数据共享Zenodo/Figshare长期存储数据

一、Conda环境锁定

# Conda环境管理 —— 可重复性的第一步

# 1. 创建项目专用环境
conda create -n my_project \           # 创建环境
    python=3.11 \                      # 指定Python版本
    numpy=1.26.0 \                     # 指定numpy版本
    pandas=2.1.0 \                     # 指定pandas版本
    -y                                 # 自动确认

# 2. 导出精确环境(包含所有依赖版本)
conda activate my_project              # 激活环境
conda env export > environment.yml     # 导出环境文件

# environment.yml 内容示例:
# name: my_project
# channels:
#   - conda-forge
#   - bioconda
#   - defaults
# dependencies:
#   - python=3.11.5
#   - numpy=1.26.0
#   - pandas=2.1.0
#   - samtools=1.18
#   - bwa=0.7.17

# 3. 别人用这个文件重建完全相同的环境
conda env create -f environment.yml    # 从文件创建环境
# → 所有软件版本完全一致!

# 4. 更严格的锁定(conda-lock)
conda install -c conda-forge conda-lock  # 安装conda-lock
conda-lock -f environment.yml \        # 生成锁文件
    -p linux-64                        # 指定平台
# → 生成conda-lock.yml,包含精确的包hash值

二、Docker容器化

# Dockerfile —— 把整个分析环境打包成容器

# 选择基础镜像(Bioconductor官方镜像包含R+常用包)
FROM bioconductor/bioconductor_docker:3.19

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    samtools=1.18-1 \                  # 指定samtools版本
    bwa \                              # BWA比对工具
    fastp \                            # 质控工具
    && rm -rf /var/lib/apt/lists/*     # 清理缓存

# 安装Python依赖
RUN pip install \
    numpy==1.26.0 \                    # 锁定numpy版本
    pandas==2.1.0 \                    # 锁定pandas版本
    scanpy==1.10.0                     # 锁定scanpy版本

# 安装R包
RUN R -e "BiocManager::install(c(      \
    'DESeq2',                           \
    'clusterProfiler',                  \
    'limma'                             \
), version = '3.19')"                  # 指定Bioconductor版本

# 复制分析脚本
COPY scripts/ /app/scripts/            # 复制脚本到容器
COPY Snakefile /app/                   # 复制Snakemake流程

# 设置工作目录
WORKDIR /app                           # 设置工作目录

# 入口命令
CMD ["snakemake", "--cores", "all"]    # 默认运行Snakemake
# Docker使用命令

# 构建镜像(给镜像打上日期标签)
docker build -t my_analysis:2026.01 .  # 构建镜像

# 运行分析
docker run \
    -v $(pwd)/data:/app/data \         # 挂载数据目录
    -v $(pwd)/results:/app/results \   # 挂载结果目录
    my_analysis:2026.01                # 使用固定版本镜像

# HPC环境用Apptainer(原Singularity)
apptainer build analysis.sif \         # 构建SIF镜像
    docker://my_analysis:2026.01       # 从Docker镜像转换

apptainer exec \                       # 在容器中运行
    --bind data:/app/data \            # 绑定数据目录
    analysis.sif \                     # SIF镜像
    snakemake --cores 16               # 运行流程

三、Snakemake可重复性流程

# Snakefile —— 可重复性分析流程示例

# 配置文件(所有参数集中管理)
configfile: "config.yaml"             # 读取配置文件

# 定义所有样本
SAMPLES = config["samples"]           # 从配置文件获取样本列表

# 最终目标
rule all:
    input:
        expand("results/counts/{sample}.counts.txt",  # 每个样本的计数
               sample=SAMPLES),
        "results/deseq2/de_results.csv"                # 差异表达结果

# 规则1:质控
rule fastp:
    input:
        r1 = "data/raw/{sample}_R1.fq.gz",    # 原始R1
        r2 = "data/raw/{sample}_R2.fq.gz"     # 原始R2
    output:
        r1 = "data/clean/{sample}_R1.fq.gz",  # 质控后R1
        r2 = "data/clean/{sample}_R2.fq.gz"   # 质控后R2
    log: "logs/fastp/{sample}.log"             # 日志文件
    conda: "envs/qc.yaml"                     # 指定conda环境
    threads: 4                                 # 使用4线程
    shell:
        """
        fastp -i {input.r1} -I {input.r2} \
              -o {output.r1} -O {output.r2} \
              -q 20 -l 50 \
              --thread {threads} \
              2> {log}
        """

# 规则2:比对
rule bwa_align:
    input:
        r1 = "data/clean/{sample}_R1.fq.gz",  # 质控后R1
        r2 = "data/clean/{sample}_R2.fq.gz"   # 质控后R2
    output:
        bam = "results/aligned/{sample}.sorted.bam"  # 排序BAM
    params:
        ref = config["reference"]              # 参考基因组路径
    log: "logs/bwa/{sample}.log"
    conda: "envs/align.yaml"                   # 比对环境
    threads: 8
    shell:
        """
        bwa mem -t {threads} {params.ref} \
            {input.r1} {input.r2} \
            2> {log} \
            | samtools sort -@ 4 \
            -o {output.bam}
        samtools index {output.bam}
        """

# 配置文件 config.yaml 示例:
# samples:
#   - sample1
#   - sample2
#   - sample3
# reference: /data/ref/hg38.fa
# annotation: /data/ref/gencode.v44.gtf

四、项目目录规范

# 可重复性项目标准目录结构

my_project/
├── README.md              # 项目说明(必须!)
├── LICENSE                # 许可证
├── .gitignore             # Git忽略规则
├── environment.yml        # Conda环境定义
├── Dockerfile             # Docker容器定义
├── Snakefile              # 主流程文件
├── config.yaml            # 配置参数
├── data/                  # 数据目录
│   ├── raw/               # 原始数据(只读!)
│   └── processed/         # 处理后数据
├── scripts/               # 分析脚本
│   ├── 01_qc.sh           # 质控脚本
│   ├── 02_align.sh        # 比对脚本
│   └── 03_analysis.R      # 分析脚本
├── envs/                  # Conda子环境定义
│   ├── qc.yaml            # 质控工具环境
│   └── align.yaml         # 比对工具环境
├── results/               # 分析结果
│   ├── figures/           # 图片
│   └── tables/            # 表格
├── notebooks/             # Jupyter/R笔记本
└── docs/                  # 文档

# 核心原则:
# 1. 原始数据永远不修改(只读)
# 2. 所有中间结果可以重新生成
# 3. 配置参数与代码分离
# 4. 每个分析步骤有日志

五、种子数固定与随机性控制

# 随机性控制 —— 可重复性的隐形杀手

import numpy as np                     # 数值计算
import random                          # Python随机数
import os                              # 系统操作

def set_all_seeds(seed=42):
    """设置所有随机种子,确保结果可重复"""
    random.seed(seed)                  # Python内置随机数
    np.random.seed(seed)               # NumPy随机数
    os.environ['PYTHONHASHSEED'] = str(seed)  # Python哈希种子

    # 如果用PyTorch
    try:
        import torch                   # PyTorch
        torch.manual_seed(seed)        # CPU种子
        torch.cuda.manual_seed_all(seed)  # GPU种子
        torch.backends.cudnn.deterministic = True  # 确定性模式
    except ImportError:
        pass

    # 如果用TensorFlow
    try:
        import tensorflow as tf        # TensorFlow
        tf.random.set_seed(seed)       # TF种子
    except ImportError:
        pass

set_all_seeds(42)                      # 在脚本最开始调用

# R语言中设置种子
# set.seed(42)                         # R中设置种子

常见报错与解决

问题原因解决方法
同样代码不同结果随机种子未固定所有随机操作设置seed
包版本冲突依赖版本不兼容用conda-lock精确锁定
Docker镜像太大安装了不需要的包用多阶段构建,精简依赖
Snakemake结果不一致配置文件有差异把config.yaml纳入Git
数据文件缺失大文件未用DVC追踪用DVC管理大文件
线程数不同导致结果差异某些工具多线程不确定固定线程数或用单线程验证

速查表

# 可重复性检查清单
□ 代码在Git中(含.gitignore)
□ 环境有environment.yml或Dockerfile
□ 参数在config文件中(不硬编码)
□ 随机种子已固定
□ 原始数据不可修改
□ 有README说明如何运行
□ 流程用Snakemake/Nextflow管理
□ 结果可一键重新生成

# 工具选择
代码版本: Git + GitHub/GitLab
数据版本: DVC (Data Version Control)
环境锁定: Conda + Docker/Apptainer
流程管理: Snakemake / Nextflow
文档:     README + Jupyter Notebook
共享:     Zenodo (DOI) + GitHub

# 核心原则
1. 版本锁定: 所有软件指定版本号
2. 环境隔离: 每个项目独立环境
3. 参数外置: 配置与代码分离
4. 自动化:   一键运行全流程
5. 文档化:   记录为什么这样做