3、常见RNA-seq数据格式:FASTQ、SAM/BAM、counts矩阵、TPM/FPKM/RPKM

做RNA-seq模型验证,最怕什么?不是算法选不对,而是数据格式没搞懂。

我记得刚入行时,拿到一个10x的单细胞项目,同事扔给我一堆.bam文件。我直接当fastq读了……结果模型训了三天,出来的结果一塌糊涂。后来才发现,连数据是什么格式都搞错了。

所以这一章,咱们把RNA-seq常见的四种数据格式彻底讲清楚。你想想看,模型鲁棒性验证的第一步,就是确保你用对了数据。

3.1 FASTQ:原始序列的起点

FASTQ是测序仪直接输出的格式。说白了,它就是一段DNA序列,外加一个质量评分。每一个read都对应四行:

@SEQ_ID
GATTTGGGGTTCAAAGCAGTATCGATCAAATAGTAAATCCATTTGTTCAACTCACAGTTT
+
!''*((((***+))%%%++)(%%%%).1***-+*''))**55CCF>>>>>>CCCCCCC65

第一行是序列标识符(以@开头),第二行是碱基序列,第三行是分隔符(通常只有一个+),第四行是质量评分。

质量评分用的是Phred+33编码。每个字符对应一个ASCII码,减去33就是质量值Q。公式很简单:

Q = -10 * log10(P)
P = 10^(-Q/10)

Q30意味着碱基出错的概率是千分之一。我在项目中通常只看Q30的比例,低于80%的样本我会直接标记为高风险。

经验之谈:质量评分是RNASeq数据清洗的第一道坎。我曾经因为忽略接头上,导致下游比对率只有60%,白费了两周时间。建议每个样本先跑FastQC,检查GC含量、重复率、接头污染这些指标。

实测项目中,我习惯把所有FASTQ文件先合并统计,再看分布。如果某个样本的Q20比例低于50%,直接标记为异常,不参与后续模型验证。

3.2 SAM/BAM:比对后的标准格式

把FASTQ比对到参考基因组后,得到的就是SAM或BAM文件。SAM是文本格式,BAM是它的二进制压缩版。

比对文件长什么样?看这段示例:

@HD	VN:1.6	SO:coordinate
@SQ	SN:chr1	LN:248956422
@PG	ID:bwa	PN:bwa	VN:0.7.17
read_1	0	chr1	10000	60	150M	*	0	0	ATCGTAGCTA...	IIIIIFFFFF...	NM:i:0	MD:Z:150

每行代表一条read的比对信息。关键的字段包括:

  • QNAME:read名称,要和FASTQ里的@行对应
  • FLAG:一个整数,用位运算表示比对状态(比如是否配对、是否唯一比对)
  • RNAME:参考序列名称(比如chr1)
  • POS:比对起始位置
  • MAPQ:比对质量,类似Q值,越高越好
  • CIGAR:比对时发生的操作,如剪接、插入、删除

我常被问到:“SAM和BAM到底该用哪个?” 答案是:存储用BAM,调试用SAM。BAM体积只有SAM的1/5,而且samtools处理起来快很多。

注意:BAM文件必须排序和索引。未排序的BAM无法直接用于差异表达分析。我见过有人直接用未排序的BAM跑featureCounts,结果计数全乱了。一定要跑samtools sort和samtools index。

3.3 counts矩阵:基因表达的基本单位

把比对好的read映射到基因上,得到的就是counts矩阵。它是表达定量最原始的形式——每个基因有多少条read被检测到。

counts矩阵长这样:

gene_id	sample1	sample2	sample3
ENSG000001.1	125	98	134
ENSG000002.2	0	1	0
ENSG000003.3	2367	2100	2456

每一行是一个基因(用ENSEMBL ID或基因名标识),每一列是一个样本,每个单元格是整数。

注意,counts矩阵的特点是整数,且服从负二项分布。这是后续差异表达分析的基础。多数工具(比如DESeq2)直接吃counts矩阵。

避坑指南:我曾经用FPKM矩阵跑DESeq2,结果差异基因一塌糊涂。因为DESeq2内部假设输入是整数counts,FPKM是小数,直接做归一化会破坏算法假设。所以从BAM到counts这一步,不能省。

生成counts矩阵的常用工具是featureCounts(subread包)和htseq-count。

featureCounts -T 8 -p -t exon -g gene_id \
  -a Homo_sapiens.GRCh38.104.gtf \
  -o counts.txt \
  sample1.bam sample2.bam sample3.bam

这个命令会输出一个表格,包含每个基因在每个样本中的read计数。

3.4 TPM/FPKM/RPKM:归一化后的表达量

counts受基因长度和测序深度的影响,不能直接用来比较不同基因或不同样本的表达水平。所以需要归一化。

三种最常见的归一化方案:

指标 全称 归一化维度 特点
RPKM Reads Per Kilobase per Million 基因长度 + 测序深度 最早出现,适用于单端测序
FPKM Fragments Per Kilobase per Million 基因长度 + 测序深度 RPKM的双端版本,考虑fragment
TPM Transcripts Per Million 基因长度 + 测序深度 先按长度归一化,再按比例缩放

它们之间的换算关系如下:

RPKM = (counts * 10^9) / (gene_length * total_reads)

FPKM = (fragments * 10^9) / (transcript_length * total_fragments)

TPM = (counts / gene_length) / sum(counts / gene_length for all genes) * 10^6

为什么我喜欢TPM?因为TPM在不同样本之间可比性最好。RPKM和FPKM对高表达基因有偏向,容易在跨样本比较时引入偏差。我在项目里,如果是做外部数据集评估,一律用TPM。

实操建议:

  1. 如果手里只有counts矩阵,用scaleCounts先转为TPM,再用于模型训练
  2. 如果已经是FPKM,可以通过公式反推出近似counts,但我建议直接拿原始的counts重算TPM
  3. 在做模型鲁棒性验证时,同时保留counts和TPM两份数据——counts用于统计检验,TPM用于表达量比较

知识体系梳理

四种格式在RNA-seq流程中的位置和关系,我用一张图来总结:

RNA-seq数据格式知识体系 FASTQ 原始序列 + 质量评分 比对 BWA / STAR / HISAT2 SAM/BAM 比对后文件 定量 featureCounts counts矩阵 整数raw counts TPM/FPKM 归一化表达量 三种归一化方法的关系 counts → 考虑基因长度 → RPKM/FPKM counts → 先长度再比例 → TPM(推荐) 模型鲁棒性验证:推荐使用TPM + counts双轨策略

从图中能清楚地看到数据流向:测序仪出来是FASTQ,比对后变成SAM/BAM,定量后得到counts矩阵,再从counts计算归一化指标TPM或FPKM。

我建议做模型鲁棒性验证时,保留三条路径:

  • 路径A:直接使用counts矩阵做差异表达分析
  • 路径B:用TPM做跨样本标准化后的比较
  • 路径C:用FPKM做原始长度的校正(如果外部数据集只有FPKM)

为什么留三条路?因为外部数据集质量参差不齐。有的公开数据只给了counts,有的只给了FPKM。掌握了这四种格式,你就能灵活应对各种情况。

最后提醒:千万别在模型输入里混用不同标准化的数据。比如训练集用TPM,测试集用FPKM,模型直接崩。一定要统一到同一个尺度。