RNA-seq数据分析概述:从测序数据到表达矩阵
做RNA-seq分析这么多年,我最大的体会就是:数据预处理的质量,直接决定了后续所有分析的成败。说白了,你后面用多牛的模型、画多漂亮的ROC曲线,如果表达矩阵本身有硬伤,那都是白搭。
这一章,咱们就把RNA-seq从原始测序数据到表达矩阵的全流程捋一遍。我会重点说清楚每个步骤到底是干什么的,以及我曾经踩过的坑。
1.1 RNA-seq分析的基本流程
RNA-seq的原始数据,说白了就是一堆几亿条的小短序列(reads)。核心任务就是搞清楚两件事:「这条read来自哪个基因?」 和 「那个基因到底有多少条read?」
我个人习惯把整个流程拆成四大块:
- 原始数据预处理——把脏数据洗洗干净(质量控制、去接头、过滤低质量数据)
- 比对或定量——把reads定位到基因组或转录组上
- 基因/转录本定量——统计每个基因或转录本上有多少reads
- 表达矩阵构建——把定量结果整理成行是基因、列是样本的表格
核心要点:不管是差异表达分析、聚类分析,还是咱们这门课要讲的ROC评估,输入数据都必须是高质量的、经过正确归一化的表达矩阵。这一步不要图快。
你想想看,如果原始数据里有残留的接头序列,或者比对参数设得不对,那下游模型评估时得到的「准确率」就是虚假的。我以前就吃过这个亏,后面会细说。
1.2 第一步:原始数据预处理
拿到下机数据后,千万别急着跑比对。先做质量评价。
1.2.1 质量评价(QC)
我通常用 FastQC 来做初步的质量评价。看一眼报告里的几个关键指标,基本就能判断这批数据能不能用。
fastqc sample_1.fastq.gz sample_2.fastq.gz -o ./qc_reports
重点关注这些地方:
- Per base sequence quality:每个碱基位置的质量得分。如果尾巴上大面积低于Q20,建议直接截短或过滤。
- Adapter Content:接头残留。如果有明显的接头峰,必须用工具去接头。
- Overrepresented sequences:看看有没有可疑的序列污染。
注意: 我曾经遇到过一个项目,FastQC报告里显示样品间质量差异很大。当时赶进度没仔细看,直接全部合并处理,结果后续差异分析结果完全无法解释。后来排查才发现是其中一个样品的测序芯片有瑕疵。这件事之后,我养成了每个样品单独看FastQC报告的习惯。
1.2.2 去除接头与低质量序列
这一步我推荐用 Trimmomatic 或 cutadapt。这里给一个Trimmomatic的常见用法:
java -jar trimmomatic-0.39.jar PE \
sample_R1.fastq.gz sample_R2.fastq.gz \
sample_R1_paired.fastq.gz sample_R1_unpaired.fastq.gz \
sample_R2_paired.fastq.gz sample_R2_unpaired.fastq.gz \
ILLUMINACLIP:TruSeq3-PE.fa:2:30:10 \
LEADING:3 TRAILING:3 \
SLIDINGWINDOW:4:15 MINLEN:36
参数简单解释一下:
ILLUMINACLIP:去接头的参数对。SLIDINGWINDOW:4:15:4个碱基为一组,平均质量低于15就截断。嗯,这个值比较宽松,通常建议改成20。MINLEN:36:过滤掉太短的reads。
小经验: 去接头这一步,不同测序平台用的接头序列不一样,一定要确认用对了适配器文件。我就犯过用错适配器文件导致大量数据被误删的错误。切记把平台确认好。
1.3 第二步:比对(Alignment)
这一步是把干净的reads映射到参考基因组或转录组上。比对工具的选型会影响后续很多细节。
1.3.1 常用比对工具
| 工具 | 特性 | 适用场景 |
|---|---|---|
| STAR | 速度快,敏感度高,能处理剪切位点 | 有参考基因组的标准RNA-seq |
| HISAT2 | 基于图基因组,内存占用比STAR低 | 大型基因组或复杂转录组 |
| Salmon / kallisto | 比对+定量一体,不需要先比对再计数 | 转录本级别的定量,轻量快速 |
我个人习惯用STAR,因为它稳定,而且输出格式比较规范。不过你要做好心理准备,STAR第一次建立基因组索引会比较慢,而且占内存。我曾经在服务器上建一个人类基因组索引,跑了将近2个小时。
1.3.2 STAR比对实战
先建立索引:
STAR --runMode genomeGenerate \
--genomeDir ./star_index \
--genomeFastaFiles GRCh38.fa \
--sjdbGTFfile GRCh38.gtf \
--sjdbOverhang 149
sjdbOverhang 设为读长减1,这个参数我建议别省。
然后比对:
STAR --genomeDir ./star_index \
--readFilesIn sample_R1_paired.fastq.gz sample_R2_paired.fastq.gz \
--readFilesCommand zcat \
--outSAMtype BAM SortedByCoordinate \
--outFileNamePrefix sample_
输出会得到一个 sorted BAM 文件。这里有个细节——为了方便下游做基因计数,我通常会要求STAR输出直接按坐标排序的BAM,省去后面再排序的麻烦。
避坑指南: 对比对结果的QC。不要只看比对率大于80%就觉得万事大吉。我曾经遇到过一个样品,比对率高达95%,但是大部分reads都比对到线粒体基因组上,显然是样品污染了。所以记得要检查比对分布——看看reads是落在外显子、内含子还是基因间区。
1.4 第三步:基因定量(Gene Quantification)
拿到BAM文件后,需要统计每个基因上有多少条reads。这一步我强烈推荐用 featureCounts(来自Subread包),速度快且好用。
featureCounts -T 8 \
-t exon \
-g gene_id \
-a GRCh38.gtf \
-o counts.txt \
sample1.bam sample2.bam sample3.bam
参数解析:
-T:线程数。-t:指定GTF中的特征类型,通常用exon。-g:分组依据,一般用gene_id。-o:输出的计数矩阵文件。
你会得到一个类似这样的输出:
Geneid Chr Start End Strand Length sample1.bam sample2.bam
ENSG000001 chr1 1000 2000 + 1000 45 32
ENSG000002 chr1 3000 4000 - 800 12 18
最后几列就是每个基因在每个样品中的原始read count。
注意: featureCounts默认是单端模式。如果你的数据是双端测序,记得加上 -p 参数,否则计数会翻倍,而且比对关系也会错。我刚开始做RNA-seq时就忘加这个参数,结果发现差异基因数量异常多,排查了好久才发现是计数翻倍了。
1.5 第四步:表达矩阵构建与归一化
featureCounts输出的counts.txt,其实就是一个原始计数矩阵。但直接用这个矩阵做下游分析是不行的。
为什么?因为不同样品间的测序深度不同、基因长度不同、GC含量不同,这些技术因素都会引入噪声。
常用的归一化方法:
| 方法 | 适用场景 | 说明 |
|---|---|---|
| CPM(Counts Per Million) | 快速预览、文库大小标准化 | 简单除以总read数,不能校正基因长度 |
| RPKM/FPKM | 基因长度+文库大小双标准化 | 适合基因内比较,不适合基因间比较 |
| TPM | 基因间比较更公平 | 先对基因长度归一化,再对文库大小归一化 |
| DESeq2 中位数比值 | 差异表达分析 | 假设大部分基因不差异表达,自动校正 |
我个人习惯在构建表达矩阵时,同时保存原始count和TPM。原始count用于差异表达分析的统计检验,TPM用于后续机器学习的特征输入。
1.6 本章小结
好了,从测序数据到表达矩阵的完整流程就这些。我再用一张图帮你串起来:
嗯,上面这个流程图把关键环节和常用工具都标出来了。你跟着这个框架走,基本不会跑偏。从原始FASTQ到最终的表达矩阵,每一步踩实了,后面做模型评估才会心里有底。
这门课后续的交叉验证、ROC曲线绘制,全部是建立在「高质量的表达矩阵」之上的。所以这一章的内容,说白了就是课程的基石。你别嫌啰嗦,打好地基比什么都重要。