BioF3 组学数据分析

01 从数据到项目结构

导出日期:2026年6月27日

01 从数据到项目结构

这一章的目标是让读者在真正动手做 bulk RNA-seq 之前,先把"拿到什么输入、打算得到什么输出"想清楚。很多项目一开始跑得很顺,到了复盘阶段才发现样本表有问题、目录结构乱、中间文件丢了。bulk RNA-seq 的数据量比单细胞小得多,但分析链条更长,更值得一开始就把项目结构定下来。

一个典型项目的输入和输出

以最常见的两组比较为例:对照 vs 处理,每组 3 个生物学重复,每个样本一次双端测序。你手上会有的东西和最后要交付的东西大致是:

阶段 输入 输出
测序中心交付 12 个 FASTQ 文件(6 样本 × 2 端)+ 基本 QC 报告
分析起点 上面这些 FASTQ 本地目录结构 + 样本表
比对 / 准比对 FASTQ + 参考基因组 + GTF 每个样本的 BAM 或 Salmon quant 目录
定量 BAM / Salmon 一份 gene × sample 的 counts 矩阵
差异分析 counts + 样本表 差异基因表(gene, log2FC, padj)
功能解释 差异基因表 GO / KEGG / GSEA 结果
交付 所有上面的结果 图 + 表 + Methods 段

"样本表"是整条链路的中心。它至少要有:样本 ID、条件、批次、测序时间、FASTQ 路径。后面每一步都要回到这张表。

项目目录

长期维护的目录结构没有标准答案,但至少应该满足"6 个月后回来还知道每个文件是什么"。一个可用的结构:

rnaseq_project/
├── README.md                # 项目背景、样本来源、关键决策
├── metadata/
│   └── samples.tsv          # 样本表,唯一可信来源
├── data/
│   ├── raw/                 # 原始 FASTQ(不动)
│   ├── qc/                  # FastQC + MultiQC 报告
│   ├── align/               # BAM 或 Salmon quant
│   └── counts/              # 合并后的 counts 矩阵
├── analysis/
│   ├── 01-qc.R
│   ├── 02-de.R              # DESeq2 / edgeR
│   ├── 03-enrichment.R
│   └── 04-figures.R
├── results/
│   ├── tables/
│   └── figures/
└── envs/
    └── env.yaml             # conda 环境,锁定版本

几个经验:

样本表怎么写

样本表是一个纯文本 TSV,越简单越好。一个最小可用版本:

sample_id	condition	batch	r1	r2
CTRL_1	untreated	1	data/raw/CTRL_1_R1.fastq.gz	data/raw/CTRL_1_R2.fastq.gz
CTRL_2	untreated	1	data/raw/CTRL_2_R1.fastq.gz	data/raw/CTRL_2_R2.fastq.gz
CTRL_3	untreated	2	data/raw/CTRL_3_R1.fastq.gz	data/raw/CTRL_3_R2.fastq.gz
TRT_1	treated	1	data/raw/TRT_1_R1.fastq.gz	data/raw/TRT_1_R2.fastq.gz
TRT_2	treated	1	data/raw/TRT_2_R1.fastq.gz	data/raw/TRT_2_R2.fastq.gz
TRT_3	treated	2	data/raw/TRT_3_R1.fastq.gz	data/raw/TRT_3_R2.fastq.gz

batch 这一列不一定用得到,但有分析经验之后你会知道:一开始就记录下来是最便宜的,事后补很贵。测序批次、试剂批次、操作人、文库类型,只要是可能引入系统偏差的变量都值得留一列。DESeq2 的 design 会直接用到这些列:

design = ~ batch + condition

参考基因组和注释

人和小鼠的参考基因组有几个主流来源:

来源 特点 推荐用途
GENCODE 人 / 小鼠注释的金标准 绝大多数项目,和 Ensembl ID 对得上
Ensembl 覆盖物种最多 非模式物种
UCSC / NCBI 字段丰富 做浏览器可视化、变异分析

基因组和注释必须来自同一个来源、同一个版本,不然基因 ID 和坐标就对不上。推荐直接下载 GENCODE 的 primary assembly + 主注释 GTF,搭配 Salmon 或 STAR 都能跑:

# 人 v44 作为例子
wget -c https://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_44/GRCh38.primary_assembly.genome.fa.gz
wget -c https://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_44/gencode.v44.primary_assembly.annotation.gtf.gz

这两个文件解压后占 6~7 GB,落到 data/reference/ 里,长期项目里这份东西是共享的,不跟单个项目耦合。

比对 vs 准比对

两条主流路线:

路线 典型工具 速度 磁盘 适用场景
全比对到基因组 STAR / HISAT2 → featureCounts 大(BAM) 需要 BAM 做可视化 / SNV / 新转录本
准比对到转录本 Salmon / kallisto → tximport 只做差异分析和富集

新项目如果只做差异表达和富集,用 Salmon 几乎是最佳选择 —— 笔记本上几分钟就能定量一个样本。下面这段是 Salmon 的典型调用:

# 建立索引(只做一次)
salmon index \
  -t gencode.v44.transcripts.fa.gz \
  -i salmon_index \
  --gencode

# 定量每个样本
for s in CTRL_1 CTRL_2 CTRL_3 TRT_1 TRT_2 TRT_3; do
  salmon quant \
    -i salmon_index \
    -l A \
    -1 data/raw/${s}_R1.fastq.gz \
    -2 data/raw/${s}_R2.fastq.gz \
    -p 8 --validateMappings \
    -o data/align/${s}
done

定量完成后每个样本会得到一个目录,里面的 quant.sf 就是转录本级别的定量结果。后续在 R 里用 tximport 聚合到基因级就进入差异分析:

library(tximport)
library(readr)

samples <- read.table("metadata/samples.tsv", header = TRUE, sep = "\t")
files <- file.path("data/align", samples$sample_id, "quant.sf")
names(files) <- samples$sample_id

# tx2gene 映射(从 GTF 生成一次就好)
tx2gene <- readr::read_tsv("metadata/tx2gene.tsv")

txi <- tximport(files, type = "salmon", tx2gene = tx2gene)
# txi$counts 就是 gene x sample 的 counts 矩阵

快速跳过:直接用 airway / pasilla

上面这套是面向真实项目的;如果只是想学习差异分析,完全可以跳过 FASTQ → BAM → counts 这一段,直接用 Bioconductor 已经打包好的 counts 数据:

后面 020304 的真实示例都用 airway,装上包就能跑,不用碰比对流程。

常见坑

坑 1:样本表用 Excel 编辑导致格式错乱

Excel 会自动把 MARCH1(基因名)改成日期、把数字前补 0 删掉、改空格成 unicode。永远用纯文本编辑器或 R / Python 维护样本表,要看的时候再 read.delim 进来。

坑 2:参考基因组版本和注释不匹配

下载 GRCh38 fasta 配 GENCODE v44 GTF 没问题;但配 v25 GTF 会出现"基因名对得上、坐标对不上"的诡异错误。fa 和 gtf 必须来自同一来源同一版本,不要混用。

坑 3:把 raw counts 当成已归一化的 TPM

featureCounts 出来的是 raw counts(整数),可以直接喂 DESeq2 / edgeR;但 Salmon / kallisto 的默认输出是 TPM 或估计 counts,给 DESeq2 时要用 tximport(..., type = "salmon") 转成 counts,不是直接读 quant.sf

坑 4:Salmon 索引用错链路

--gencode 标志只对 GENCODE 来源的转录组用,Ensembl 来源的转录组不要加 --gencode。否则 transcript ID 在去版本号时会出错。

坑 5:把样本目录命名成数字开头

Linux 下排序看上去 1.fastq 2.fastq 没问题,但 R 读进来当数据框列名时会自动加 X 前缀(变成 X1X2)。样本 ID 一律用字母开头S1CTRL_1),下游脚本省心。

下一步

接着深入

横向延伸

参考资源