做RNA-Seq项目这几年,每次数据下机我几乎雷打不动都会跑一遍RseQC。它是李恒军等人开发的一套RNA-Seq数据质控工具集合,功能覆盖比对结果统计、文库链特异性判断、reads在基因组区域的分布、剪接位点饱和度、基因覆盖均匀度等。一句话说清楚:RseQC就是帮你判断一个RNA-Seq文库到底做得好不好、比对结果能不能放心往下游走。这套工具对刚接触生信的同学尤其友好,命令短、输出直观,不需要写脚本就能读懂结果。
如果你正在做转录组测序,手头刚拿到BAM文件,或者想评估一批别人处理好的数据靠不靠谱,这篇文章适合你。我会从零开始,把安装、注释文件准备、核心模块实操到结果解读整个流程完整走一遍,顺带把这几年代码和踩坑经验都写进去,保证你照着操作就能得出和实际项目一致的质控判断。
1. RseQC能做什么,为什么要单独做一轮质控
1.1 RseQC在整个RNA-Seq分析流程中的定位
RNA-Seq的标准流程通常是:原始fastq比对到参考基因组,得到BAM文件,然后进入表达定量、差异分析、可变剪接分析等下游环节。问题是,比对完直接跑定量的人太多了,结果经常被隐藏的坑坑掉:文库链特异性搞错了导致表达量完全反义、rRNA污染导致内含子区域reads比例异常、RNA降解导致3'端偏好性严重、测序深度不够导致剪接位点无法饱和。这些坑在定量阶段可能不会直接报错,但会悄悄影响所有下游结果。
RseQC就是专门用来干这个的。它把常见的RNA-Seq质控指标封装成一个个独立脚本,输入是BAM文件加注释BED文件,输出是清晰易读的统计表格和PDF可视化图。整个工具体量不大,安装极其简单,运行速度快,单线程跑完一个样本一般只要几分钟到十几分钟,比FastQC处理fastq的那套思路更贴近RNA-Seq特有指标。
1.2 到底哪些场景该用、哪些场景没必要用
RseQC适合的场景有三类:一是自己刚比对完一批样本,想快速确认文库质量;二是从公共数据库下载了别人上传的RNA-Seq数据,准备做整合分析前先统一检查;三是已经发现下游结果异常,回头排查是不是数据质量问题。只要你手头有BAM文件,就有理由跑一轮RseQC。
不需要用RseQC的场景也有:比如你已经确定文库构建良好、链式信息明确、样本QC报告齐全,只是想快速看个总体比对率,samtools flagstat可能就够了。RseQC更适合系统性的几十项指标综合评估,而非单点快查。另外,如果你处理的是small RNA-Seq或某些特殊建库策略(如UMI标记),RseQC部分指标可能会失效,需要搭配其他工具一起判断。
2. 从零开始安装:环境、依赖和一键验证
2.1 安装前先想清楚这三件事
RseQC本身是个Python包,安装过程并不复杂,但我在实操中发现很多新手卡住的点其实在环境层面,而不是RseQC本身。第一个要决定的是Python版本。新版RseQC(4.0.x及以上)要求Python 3.7以上,目前我用的4.0.1版本在Python 3.9、3.10下都跑得很稳。如果你系统里还是Python 2.x,那先升级环境再谈安装。
第二个要决定的是包管理器。我强烈建议先用conda/miniconda建一个独立的RNA-Seq分析环境,再在这个环境里装RseQC。原因很简单:RseQC依赖pysam、numpy、pyBigWig等底层库,这些库版本间冲突概率不低,用conda隔离能避免把系统级Python环境搞乱。独立环境还能方便多项目多版本并行,换一台服务器也不至于反复踩依赖坑。
第三个要想清楚的是是否需要带绘图依赖。RseQC的很多脚本会额外调用R脚本画图,比如geneBody_coverage产生的PDF图其实依赖R的geneBodyCoverage脚本。如果只是跑统计不看图,不装R也能输出表;但想拿到可视化结果,就得保证R及必要包就绪。我最常用的做法是conda环境里同时装好R和R的optparse等包,省得后面补装。
2.2 两种主流的安装方式及实操命令
第一种方式是用conda。先创建一个干净的环境,然后从bioconda频道安装,命令如下:
conda create -n rnaseq python=3.9 -y conda activate rnaseq conda install -c bioconda -c conda-forge rseqc安装完成后用rseqc自带模块验证一下环境是否能正常导入依赖库:
python -c "import RSeQC; print(RSeQC.__version__)"第二种方式是用pip。如果你对conda不熟悉,或者已经在虚拟环境里,pip也一样方便:
pip install RseQCRseQC的官方包名是RseQC,注意大小写。pip会把rseqc脚本直接装到环境的bin目录下,同时带出pysam、numpy、pyBigWig等依赖。装完以后,用以下命令确认所有脚本都可用:
which bam_stat.py read_distribution.py infer_experiment.py geneBody_coverage.py如果这四条都能找到,说明核心模块都装好了。如果提示找不到命令,多半是环境的bin目录没加入PATH,用conda activate激活环境后应该能解决。
2.3 老版本残留和新手经常踩的安装坑
RseQC在3.0.x时代还支持Python 2,很多老教程里的命令和分析思路是当年的环境。网上搜索出来的安装教程有些是好几年前的,直接copy之后经常会遇到类似“ModuleNotFoundError: No module named 'RSeQC'”这类问题。这里有个经验:不要混用pip和conda安装同一个包,也不要在一个环境里pip upgrade pysam——RseQC对pysam的版本比较敏感,某些pysam新版本会和旧版RseQC不兼容。
我在一台新服务器上踩过最典型的坑是conda解算依赖特别慢。解决方法是把频道优先级配置好,把conda-forge和bioconda放到默认频道前面,或者直接用mamba代替conda:
conda install -n base mamba -c conda-forge -y mamba create -n rnaseq -c bioconda -c conda-forge rseqc -ymamba的依赖解析速度比conda快很多,尤其当bioconda依赖树比较复杂的时候,能节省大量等待时间。实际跑生信项目时,我也更推荐mamba,这不是赶时髦,是真的能避免“装包装半小时”的尴尬。
3. 准备注释文件:这一步做不好后面全白搭
3.1 为什么RseQC不能直接用GTF
RseQC几乎所有模块都要求输入一个BED格式的注释文件,问题来了:大多数人手里现成的注释文件是GTF/GFF——比如GENCODE或Ensembl的注释。RseQC虽然界面简单,但官方推荐的输入并不是GTF,而是BED。这个设计背后有历史原因:RseQC内置的很多分析脚本最早是基于UCSC基因注释体系写的,BED里可以直接表达基因、转录本、CDS、UTR区域的坐标关系,而且用BED能避免解析GTF属性字段时因attribute复杂度差异带来的边界问题。
我第一次用RseQC时直接扔了个GTF进去,报错提示一堆,当时还以为是格式不对,后来看了文档才发现它对GTF支持不佳,需要提前转成BED。所以我们要在真正分析之前,先把GTF转换成RseQC能吃的BED。转换以后,BED文件里通常会包括基因名、转录本名、染色体号、起止位置、正负链等信息,并且会标注基因区域类型(exon、CDS、UTR等)。RseQC读取BED时会自动划分区域,因此是关键一步。
3.2 从GTF到BED的三种常用转换思路
第一种是用UCSC的工具链。UCSC提供了gtfToGenePred和genePredToBed两个小程序,组合起来就能把绝大多数GTF转换为BED。操作步骤是先把GTF转成genePred中间格式,然后从genePred转成BED:
gtfToGenePred -genePredExt hg38.refGene.gtf hg38.refGene.genePred genePredToBed hg38.refGene.genePred hg38.refGene.bed这种方法的好处是UCSC官方维护,转化逻辑成熟;缺点是需要单独下载安装UCSC工具,且对非标准GTF的容忍度一般。
第二种是用RseQC自带的脚本。RseQC包里其实带了一个gtf2bed.py,可以把GTF直接转换成BED。这个脚本以前在RSeQC-3.x版本里就有,新版本继续保留了:
gtf2bed.py hg38.gtf > hg38.bed这个脚本比较轻量,不需要额外下载工具,但我个人觉得它在处理非常复杂的可变剪接注释时可能不如UCSC工具链精细。如果只是常规人类、小鼠转录组建库,用gtf2bed.py完全够用。
第三种是用更通用的工具,比如bedops、agat等。但这些不是必须的,我只是给有特定需求的朋友提个醒。无论用哪种方式,转换完成后都必须抽几行检查格式。BED格式至少要有12列才算完整,其中第九列是外显子数,第十列是外显子长度列表,第十一列是外显子起始位置列表,第十二列是颜色等附加信息。例如:
head -5 hg38.bed如果看到12列完整、坐标没有错乱,那这个注释文件大概率能用。还有个小细节:RseQC的某些模块(比如read_distribution)会按染色体名精确匹配BAM里的染色体名,常见坑是GTF里染色体名带“chr”前缀,而BAM里却不带,或者反之。比如Ensembl的注释经常是1号染色体,而UCSC是chr1,两边不一致时所有统计都为零,这个要提前用samtools view看看BAM的染色体命名方式,再调整注释文件。
3.3 注释文件版本和物种匹配的硬指标
注释文件版本、物种必须和你的数据一致,这个看起来是废话,但出错率极高。我见过有人用hg19注释跑hg38的数据,bam_stat还能正常出结果,到了read_distribution就出现“Total tags”骤降、intergenic比例畸高,最后排查才发现是注释版本不对。经验做法是:拿到BAM先确认参考基因组版本(从比对日志、header、或sample sheet里看),然后去GENCODE官网(gencodegenes.org)或Ensembl下载对应版本的GTF和小鼠、人等物种的注释;注意下载GTF时选“genome annotation”而不只是“transcript sequences”。
如果要用UCSC的工具和注释风格,也可以在UCSC Table Browser里直接选human hg38,选“NCBI RefSeq”或“GENCODE v××”,输出格式直接选“BED”,一步到位导出,不需要自己转格式。这样拿到的BED更干净高效。需要特别注意,如果跑的是非模式物种,没有标准注释,那RseQC很多模块分析意义会打折——没有好注释,质控指标就失去了参照系,此时建议结合bam_stat和自定义rRNA区间来判断基本质量。
4. 核心模块实操与结果判读
4.1 bam_stat.py:先给全库比对情况做个总体检
安装和注释都齐了,正式分析从bam_stat.py开始。这个脚本是RseQC所有模块里最基础的,输入可以不用BED注释文件,只需要一个按要求排序并索引过的BAM文件。命令长这样:
bam_stat.py -i sample.sorted.bam运行后会在屏幕上打印一个可读性很强的统计报告。常见关键字段包括:Total records(总比对记录数)、Unmapped reads(未比对上的reads数)、Non primary hits(非主要比对,比如次要比对)、Properly paired reads(正确配对比例)、reads mapped to plus/minus strand(正负链reads比例)等。
我在实际项目中会重点看几个阈值。Total mapped reads比例一般要在80%以上,比较理想的是85%-95%。如果比对率太低,优先怀疑样本污染、接头残留或参考基因组不匹配。Properly paired reads的比例也非常关键,双端文库低于70%通常意味着片段插入异常或比对参数不对。另外要注意Non primary hits,如果这个值过高,可能是重复序列比对多,说明文库复杂度低,或者比对策略没开“--outFilterMultimapNmax”这类限制。
bam_stat还有一个实用场景是判断是否链特异性文库。虽然infer_experiment更专业,但bam_stat里会给出正负链reads数,如果正负链比例明显失衡(比如90%都在同一条链),那基本说明文库是链特异性的。如果你手头的数据是链特异性建库,并且判断错了方向,下游所有定量结果都会反掉,因此bam_stat的这一步能提前预警。
4.2 infer_experiment.py:链特异性判断必须做的对照实验
链特异性是RNA-Seq文库最容易被忽视但也最影响下游结果的属性。判定方法说起来很简单:要看reads比对上基因组后,相对于转录本方向是第一链还是第二链。RseQC的infer_experiment.py会随机抽取一组reads,匹配注释转录本的方向,然后给出两种文库模式的解释比例。
先看用法:
infer_experiment.py -r hg38.bed -i sample.sorted.bam输出类似这样:
This is PairEnd Data Fraction of reads failed to determine: 0.03 Fraction of reads explained by "1++,1--,2+-,2-+": 0.85 Fraction of reads explained by "1+-,1-+,2++,2--": 0.12这里的“1++”表示read1比对到正义链,“2--”表示read2比对到反义链。模式“1++,1--,2+-,2-+”对应的是FR链式建库,也就是通常说的“第一链文库”(stranded first-strand),Illumina的很多试剂盒都是这种;而“1+-,1-+,2++,2--”对应的是RF建库,也就是“第二链文库”。实际判断时,哪个模式的比例高,文库就属于哪一类。如果两个模式比例各占一半,那基本就是非链特异性文库。
这个模块虽然叫infer,但它只是“基于数据推断”,并不是金标准,最终判断要结合建库试剂盒的官方文档。比如你用某品牌的链式建库试剂盒,说明书明确说reads反义链保留,那infer_experiment的结果只是作为验证。如果两者矛盾,优先怀疑试剂盒批次问题,其次再考虑注释方向是否正确。实际项目里,我自己用infer_experiment验证过多次,它和试剂盒说明一致的概率很高,但对注释文件错误容忍度低,注释方向反了,这个模块的结果也会完全反转。
4.3 read_distribution.py:reads落点图谱暴露文库纯度
read_distribution.py是另一个高频使用的模块。它的作用是统计reads落在基因不同区域的比例——CDS、5'UTR、3'UTR、内含子、基因间区等,从而判断文库构建质量和RNA纯度。用法是:
read_distribution.py -r hg38.bed -i sample.sorted.bam输出里会有一张区域统计表。每个区域给出Tag数、每百万Tag数、占总Tag数百分比。我判读时一般关注三个比例:CDS+UTR总占比(coding区域占比),Intronic占比,Intergenic占比。一个合格的RNA-Seq文库,coding区域(包括CDS和UTR)占比应该在60%-80%以上。如果Intronic占比过高,常见原因包括:RNA提取时基因组DNA污染、文库中的pre-mRNA没有被彻底去除、注释不够新导致内含子区域实际是未注释的外显子等。
Intergenic占比高的情况则要谨慎,可能是注释不完整、样本交叉污染,或者比对参数太宽松导致reads乱比对。RNA-seq里允许少量intergenic reads存在,但如果超过20%,我会回头检查样本是否混有DNA或宏基因组序列。还有一个小技巧:如果5'UTR和3'UTR占比严重失衡,比如3'UTR比例远超5'UTR,可能提示RNA降解,因为降解后3'端片段更容易被捕获。更精确的判断可以再跑一个geneBody_coverage。
需要注意的是,read_distribution本身不考虑多读段(multireads)的影响,它统计的是“bam里所有比对记录的tags”,所以如果bam没过滤多比对,intergenic比例会被虚高。建议在比对时或后续过滤阶段,保留唯一的primary比对(如samtools view -F 260或STAR的NH:i:1过滤)再跑质控,这样结果更接近真实转录组构成。
4.4 geneBody_coverage.py:查RNA降解和文库偏好的照妖镜
geneBody_coverage.py这个模块给出的信息是我个人在样本QC时最看重的。它把每个基因从5'端到3'端平均划分成100个bin,统计reads在bin中的覆盖度,并输出一条均一化覆盖曲线。如果曲线从左到右平稳,说明转录本各区域被均匀覆盖;如果右边明显抬高,说明3'端偏好——这通常是RNA降解或建库时捕获偏长片段的特征;如果左边明显抬高,可能是5'端建库偏好或反转录提前终止。
实际操作命令:
geneBody_coverage.py -r hg38.bed -i sample.sorted.bam -o sample_gb运行后会生成sample_gb.geneBodyCoverage.txt和sample_gb.geneBodyCoverage.r脚本,以及最终的PDF图。如果不想要R自动出图,把出的.r脚本交给R执行也行。我一般同时保留txt文件和PDF图,txt里第一行是100个位置的覆盖值归一化后的相对值,意义是“均一化覆盖度剖面”,方便后续批量比较。
拿到曲线后,我给自己定的可接受标准是:曲线3'端/5'端覆盖比在0.8-1.2之间,且没有明显断层。如果只做polyA富集的RNA-Seq文库,3'端偏高一点是正常的,但不会偏太多。如果curve是一路向右上倾斜的平滑斜坡,基本上RNA降解是主因。这种情况下downstream差异分析表达量会出现假基因上调等假象,建议测序前重抽RNA或测序后谨慎过滤3'端偏好样本。RseQC官方的文档和经验建议是,TIN值或geneBody曲线异常时,可以考虑把相关样本从批次分析中剔除,或者至少做批次校正时作为协变量,不能直接当作正常样本一起比较。
4.5 junction_saturation.py:测序深度够不够,就靠它说话
另一个判断测序深度的模块是junction_saturation.py。它的思路很巧妙:把比对上的reads随机抽取出多个子集(比如10%、20%……100%),在每个子集里统计已知和未知剪接位点的检测个数,然后看随着数据量增大,剪接位点数是否趋于饱和。如果能达到平台期,说明现有测序深度足够支撑剪接位点检测;如果还在快速上升,说明需要追加测序量,否则可变剪接类分析会不完整。
用法:
junction_saturation.py -r hg38.bed -i sample.sorted.bam -o sample_js -m 1 -M 100这里-m和-M控制抽样阈值范围,-m 1表示最低抽样1%,-M 100表示最高抽样100%。一般默认参数就够。运行后输出每个抽样比例下检测到的junction数量。RseQC会画一个以测序比例为横轴、被检测到剪接位点数为纵轴的曲线,曲线如果后期基本平缓,饱和度好。
我看到很多人在实际项目里不看这个模块,因为它的默认输出是txt格式,需要解释;但如果你的下游要分析可变剪接,这个模块绝对值得多跑。得到的结论也能指导你决定是否要合并多个lane的数据,或者判断某个样本的测序深度是否落在同一水平线上。我见过同一批样本中,一个样本的junction saturation曲线只到70%就开始平缓,另一个到90%还在上升,这意味着后者潜在的可变剪接信息量远高于前者,后续差异剪接分析时容易被误判为两类生物学特征。
4.6 read_duplication.py、inner_distance.py、clipping_profile.py等其他模块
RseQC这套工具还有很多模块,它们虽然使用频率略低于前四个,但特定场景下能救命。
read_duplication.py统计reads重复程度。重复率高说明文库复杂度低,常见于超量PCR扩增、起始RNA量不足。RNA-Seq对PCR重复比DNA-Seq容忍度高一些,因为高表达基因的reads天然会有重复,但如果整体重复率超过50%,就要怀疑扩增过度,后续定量需要谨慎处理重复reads。
inner_distance.py统计双端reads的插入片段长度分布,用于确认RNA片段化后的长度。出现多个主峰或峰值明显偏宽,说明片段化或size selection有问题。这个模块对判断链式建库方向也有帮助,因为FR和RF模式下inner distance的分布参照不同,不过一般不用它做方向判断。
clipping_profile.py统计reads在剪接位点附近的软裁剪情况,可以用来评估比对器剪接位点识别是否准确、是否存在系统性比对错误。对一些非模式物种或者注释不完整的物种,这个模块能暴露很多比对器无法直接提示的问题。这个模块的输出图不太直观,新手可以先不管,等项目做熟了再回来看。
5. 全流程综合示例:一个样本从BAM到质控报告
5.1 串联命令与输出整理
我习惯把RseQC的多个模块串成一段脚本,一次性跑完所有核心指标,省得每个模块单独输入输出。这里给一个我实际项目里用的模板,假设样本名为sample,工作目录下有sample.sorted.bam、sample.sorted.bam.bai和hg38.bed:
# 1. 最基础的BAM整体统计 bam_stat.py -i sample.sorted.bam > sample.bam_stat.txt # 2. 链特异性推断 infer_experiment.py -r hg38.bed -i sample.sorted.bam > sample.infer_experiment.txt # 3. Reads在基因区域的分布 read_distribution.py -r hg38.bed -i sample.sorted.bam > sample.read_distribution.txt # 4. 基因体覆盖均一性 geneBody_coverage.py -r hg38.bed -i sample.sorted.bam -o sample_gb # 5. 剪接饱和度 junction_saturation.py -r hg38.bed -i sample.sorted.bam -o sample_js -m 1 -M 100 # 6. 文库复杂度 read_duplication.py -i sample.sorted.bam -o sample_dup这样跑完以后,目录下会生成一堆以sample开头的文件,我习惯把每个样本的所有质控文件统一放到sample_qc目录里,方便后面批量汇总。对于大量样本的项目,我会在脚本里加一个循环,批量跑完每个样本,然后统一整理成一个总表。RseQC本身没有多线程并行设计,每个模块都是单线程,所以我用xargs和shell循环把样本并行起来:
cat sample_list.txt | xargs -P 8 -I {} sh -c 'bam_stat.py -i {}.sorted.bam > {}_qc/{}.bam_stat.txt'并行度8是我在32核服务器上的经验值,既要利用机器资源,又不能让IO成为瓶颈。
5.2 看懂输出:哪些数值该记进质控汇总表
跑完RseQC不等于质控完成,关键是能把数值汇总成可对比的表格。我在项目里会整理一个Excel或csv,每个样本一行,核心字段包括:比对率、唯一比对率、properly paired率、链特异性模式及比例、CDS/UTR/Intron/Intergenic占比、geneBody 3'端与5'端覆盖比、剪接位点饱和拐点、重复率。这样一旦某个样本某个指标异常,横向对比就能一眼锁定问题。
下面是一个示例汇总表的片段,方便理解格式:
| 样本 | 比对率(%) | 唯一比对率(%) | 链式模式 | CDS占比(%) | Intron占比(%) | Intergenic占比(%) | 3'/5'覆盖比 | 重复率(%) |
|---|---|---|---|---|---|---|---|---|
| S1 | 92.3 | 78.5 | FR | 55.0 | 18.2 | 12.1 | 1.1 | 25.4 |
| S2 | 84.1 | 65.2 | FR | 40.3 | 30.4 | 18.6 | 1.5 | 41.2 |
| S3 | 90.7 | 72.3 | RF | 67.0 | 12.4 | 9.8 | 0.9 | 28.7 |
从这张表就能很快判断:S2的比对率偏低、CDS占比偏低、内含子占比高、3'端偏置大、重复率高,是一个明显有问题的样本。S1和S3分布于合理范围,可以进入下游分析。我见过不少团队做PCA或差异分析时,异常样本混在其中拉偏结果,其实只要先用RseQC做一轮这种汇总对比,完全可以提前排除掉坏样本。
5.3 RSeQC结果与下游分析衔接的实操建议
质控本身不是终点。拿到RseQC结论以后,我通常会在下游分析里做几个联动操作:第一,如果某样本链特异性和其他样本不一致,下游定量时需要分开用不同参数,或者干脆删除该样本;第二,如果某样本内含子比例特别高,定量时考虑加一个低表达基因过滤阈值,避免rRNA或内含子残留干扰;第三,如果不同样本的基因覆盖曲线差异大,差异分析时把3'/5'覆盖比作为协变量放进模型,算是一种简单的统计校正。
很多朋友问要不要在RseQC之后再跑MultiQC把结果汇总起来——可以,特别是样本量大的时候,MultiQC支持RseQC的多模块输出,能自动读入并生成交互式报告。但是MultiQC并不是必需,它只是汇总展示,替代不了你对每个指标的解读和判断。所以我建议在小项目里就用RseQC原始输出自己整理表格,样本多了再上MultiQC批量看趋势。最终的项目交付报告里,通常我会把RseQC的bam_stat和read_distribution表格直接附在补充材料里,审稿人和合作者看了也更容易认可数据质量。
6. 常见报错与避坑指南
6.1 报错对照速查表
我整理了几个RseQC运行中的高频问题,都来自实际项目,对照排查效率很高。
| 报错信息或现象 | 主要原因 | 解决办法 |
|---|---|---|
| ValueError: not enough values to unpack | 注释BED格式不对,某些行缺少12列 | 检查BED每列数,用UCSC工具重新转换 |
| Chromosome not found in annotation | BAM染色体名和BED不匹配 | 用samtools view -H对比两个文件的染色体命名,统一chr前缀 |
| ModuleNotFoundError: No module named 'RSeQC' | 安装不完整或环境切换错误 | conda环境中重新安装,检查python -c "import RSeQC" |
| bam_stat.py出现“unable to open BAM” | BAM未排序或没有索引 | 用samtools sort生成sorted bam,再执行samtools index |
| geneBody_coverage生成txt但PDF为空 | R依赖缺失或R脚本执行失败 | 检查R环境及optparse包,或直接用.r脚本手动跑 |
| 所有模块输出均为0 | BAM里reads的染色体命名与BED严重不同 | 对比染色体名,给BAM重新添加chr前缀或用sed统一注释 |
6.2 我遇到过的最隐蔽的坑
第一个坑是BAM的sort顺序。RseQC大部分模块要求BAM按坐标排序且建立索引,但有些工具(比如STAR自带输出)默认可能是按query name排的,如果忘了sort,bam_stat可能还能跑,但read_distribution和geneBody_coverage会出现统计为零或异常低。我的习惯是:所有RNA-Seq比对完,统一走一遍samtools sort和index,再进RseQC。
第二个坑是链特异性判定的方向问题。有一次我用某试剂盒做链式建库,说明书说保留第二链,但infer_experiment结果明确显示FR(第一链)模式占优,当时对照试剂盒反复核对才发现,原来是上游转录本注释文件的方向和BAM比对时参考序列方向有出入。这种情况最容易误判文库类型。最终解决办法是:以infer_experiment结果为主,但同时也跑一个已知的对照样本(比如用同批次小鼠RNA的某个样本)去校准方向,如果对照样本的试剂盒信息明确,就能判断是试剂盒批次问题还是参考注释问题。
第三个坑是geneBody_coverage曲线出现锯齿状图形。看着像不是标准曲线,排查了发现有部分基因的外显子极短,100个bin的分辨率不够,导致覆盖在局部分段式分布。这个问题可以通过RseQC自带参数里给基因加权重或者改用大片段转录本子集来缓解。不过在绝大多数常规项目里,这个锯齿不会影响整体判断,不用过度处理。
6.3 批量质控时的效率优化技巧
当样本量到几十上百时,RseQC单线程跑就会显得慢。我的处理是三层优化。第一层是并行:用xargs -P并行跑多个样本,这招立竿见影。第二层是减少注释解析耗时:把BED文件提前按chr分块,每个模块只读取需要的染色体区域,能缩短大量IO时间。第三层是合理裁剪:如果只是做快速批次质控,不一定每个样本都跑junction_saturation,这个模块相对耗时,可以先跑bam_stat、infer_experiment、read_distribution、geneBody_coverage四个核心模块,等初筛出现问题再针对性补跑其他模块。
我还建议把RseQC纳入固定的分析流程,每次比对完成就自动触发,而不是等所有数据都齐了再一次性采集。这样不仅能及早发现问题样本、及时补测或重处理,还能减少大批量并行时计算资源的集中争抢。
7. 写在最后的一些个人体会
RseQC在RNA-Seq质控里属于“小而不小”的工具——安装体积小,单个模块功能单一,但整套工具用熟了以后,你会发现自己对一批数据的质量判断会有一个体系化框架。我做各类转录组项目这些年,RseQC几乎是我每次都会预设的一道关卡,它给到的判别维度非常扎实。有时候数据分析结果异常复杂,回头查质控报告,往往能早早在源头定位问题。
最后分享一个小技巧:不管跑什么模块,顺手把每个样本的RseQC结果版本号和运行命令都保存下来,字段里加上GTF/GENCODE版本、参考基因组版本、比对软件版本。质控报告如果缺少版本信息,过两个月再看很难复现,这条是吃过亏以后才养成的习惯。希望这篇实战指南能帮你少踩一些我踩过的坑,让RNA-Seq数据从第一步就走在踏实的轨道上。