software

featureCounts 实跑七组计数规则,为什么同一个 BAM 会得到不同的基因计数

作者:发布于 2026-11-15约 11 分钟阅读
同一个 BAM,为何计数不同。七组实际计数,追溯每一份贡献的来源。计数单位,先确认按什么单位计数,双端输入与按片段汇总是两个设置。6 ≠ 5,统计数与权重和可以不同,多位置比对数不等于独立片段数。链方向,负链基因不等于反向文库,核对读段相对转录方向的关系。

两个分析人员拿到同一个比对文件,最后的基因计数却不一样,问题不一定出在文件损坏。一个人按单条读段计数,另一个人按双端片段计数,一个人丢弃多位置比对,另一个人允许分摊,得到不同数字完全可能。真正需要核对的是每一个数字对应什么对象,以及哪些证据被接受、排除或者重复分配。

featureCounts 属于 Subread 软件包,负责把已经比对的读段分配到注释定义的区域。它可以处理基因、外显子等不同计数对象。本篇实际安装并运行的是其中的 featureCounts,没有运行 Subread 或 Subjunc 比对器。我们构造一份小到可以逐行核对的注释和比对文件,跑七组参数,解释双端、重叠、多位置和链方向如何改变结果。这里不比较速度,也不把规则测试当成真实样本的表达分析。

同一个 BAM,为何计数不同。七组实际计数,追溯每一份贡献的来源。计数单位,先确认按什么单位计数,双端输入与按片段汇总是两个设置。6 ≠ 5,统计数与权重和可以不同,多位置比对数不等于独立片段数。链方向,负链基因不等于反向文库,核对读段相对转录方向的关系。
七组实际计数,追溯每一份贡献的来源

先分清注释区域和汇总对象

常见命令中的 -t exon -g gene_id 包含两层意思。首先选出注释第三列为外显子的行,再根据属性中的基因编号汇总。一个基因可以有多个外显子,也可以因为存在多个转录本而出现重叠的外显子记录。按基因汇总时,不应把每一行注释都想成一张独立的计数票。

本次设计了三个基因。正链基因 A 有两个外显子,正链基因 B 与其中一个发生重叠,负链基因 C 位于另一区域。它们都在同一条人工染色体上,坐标采用注释文件的一基制闭区间。这样既能观察同一基因的多个外显子,也能观察不同基因相互重叠的情况。

基因 链 外显子坐标
A 正链 101–200、301–400
B 正链 151–250
C 负链 601–750

这里容易出现的错误,是先把每个外显子的计数相加,再把这个和当成基因计数。一个跨越同一基因多个外显子的片段可能被重复加入。featureCounts 的基因层级汇总有自己的去重和归属规则,不能用一个没有核对对象的求和操作代替。官方说明区分了区域本身与按标识组合的汇总对象,阅读输出前应先弄清自己使用哪一层。featureCounts 官方说明

六个片段为什么会变成十四条记录

输入中只有六个不同的片段名称。其中一个片段有两个比对位置,因此产生两组双端比对,其余五个片段各有一组。总计七组比对、十四条 SAM 记录。这个关系是后面核对统计表的关键,不能看到十四条记录就认为测到了十四个独立分子。

六个设计分别对应明确归属 A、明确归属 C、存在两个比对位置、不落在任何外显子、单端存在基因重叠,以及双端都存在基因重叠。每条读段长四十个碱基,序列和质量列使用占位字符。坐标、标记、配对关系以及多位置标签才是此次计数测试的输入事实。因此,这份 SAM 适合检查计数规则,不适合评估比对准确性,也不能用于研究测序质量。

多位置片段的两组比对都带有 NH:i:2,并区分主比对与次比对。这让程序知道同一片段存在多个位置。如果上游文件没有正确保留这些标签,后续允许多位置和分摊的参数就可能脱离原来的证据。检查 BAM 时不能只看染色体坐标,还要核对决定计数行为的标签是否完整。

安装和完整复现范围

本次使用的容器标签为 subread:2.1.1--h577a1d6_0,程序实际报告版本二点一一点一。公开复现脚本进一步锁定镜像摘要,避免标签指向改变后无法重现。脚本在 Linux 主机上生成输入、调用容器并读取输出,容器内部不要求安装 Python。

docker pull quay.io/biocontainers/subread:2.1.1--h577a1d6_0
docker run --rm quay.io/biocontainers/subread:2.1.1--h577a1d6_0 \
  featureCounts -v

# 解压复现包后,在对应工具目录执行
python3 run.py ./practice

脚本包含七次实际计数,每次退出码均为零,保存计数矩阵、分类统计、逐条归属记录和运行日志。本文展示的数字均来自这些输出。小输入让我们能够解释每次变化,却不能用于推断大规模队列的吞吐量、内存消耗或某种文库在真实项目中的保留率。

第一个对照,双端输入不一定按片段计数

在本次版本中,-p 用来声明输入包含双端读段,还需要 --countReadPairs 才按片段汇总。我们只改变这一个选项,A 的计数从二变成一,C 从二变成一,而 B 仍然是一。日志也明确记录第一组没有开启读对计数,第二组开启了。

# 按单条 read 计数
featureCounts -T 2 -t exon -g gene_id \
  -a genes.gtf -o reads.txt -p input.sam

# 按双端片段计数
featureCounts -T 2 -t exon -g gene_id \
  -a genes.gtf -o fragments.txt \
  -p --countReadPairs input.sam

B 为什么没有简单地减半?因为计数变化取决于实际归属,不能机械地把所有基因除以二。设计中的一个片段,第一端同时接触 A 和 B,第二端只落在 B。按单条读段处理时,第一端被标为歧义,第二端贡献给 B。按片段处理时,本次程序把这组配对证据整体归给 B。两种方式下它都只贡献一个 B 计数。

这也是最值得保留逐条分配文件的地方。本次用 -R CORE 导出每条读段或片段的归属,才确认这一现象。只看最终矩阵,容易把它误判为程序少算或者多算。实际项目发现两套矩阵不一致时,先抽取有差异的基因及其邻近区域,核对几条代表性片段,通常比盲目重跑全部样本更有效。

第二个对照,一个位置跨多个基因

另一种片段的两端都落在 A 与 B 的重叠区域。默认片段计数把它标为歧义,没有加入任何基因。允许重叠分配后,这个片段可以分别对两个基因贡献计数,前面那个只有一端发生重叠的片段也会受到规则变化影响。

我们以片段模式为基线,分别加入允许重叠、允许重叠并分摊,以及同时允许多位置并分摊。表中的名称代表整组设置,具体参数在后文对应,不应把某个结果归因于单一字母。

规则 A B C
单条读段 2 1 2
默认片段 1 1 1
重叠全计 3 2 1
重叠分摊 2 1 1
多位置分摊 2.5 1 1.5
正向链 1 1 1
反向链 0 0 0

仅加入 -O 时,一个片段可以向多个基因各贡献一份,所以基因计数总和可能大于成功分配的片段数。本次重叠全计组的三个基因加起来是六,而统计表成功分配为四。两个数字的单位不同,一个是基因累计贡献,一个是通过分配的比对单位,不能因为不相等就直接认定输出异常。

加入 --fraction 后,跨多个目标的贡献会按规则分摊。这次重叠分摊组的基因总和变为四,与成功分配数相符。但这种相等是此次输入和参数下的结果,不是所有数据都必须满足的恒等式。

第三个对照,多位置和多基因是两种问题

同一条染色体坐标上的一组比对可以覆盖多个基因,这是重叠问题。同一片段可以分别比对到相距很远的位置,这是多位置问题。它们可以同时发生,也可以分别存在。只加允许重叠的选项,并不会自动接受多位置比对。

本次多位置片段分别落在 A 与 C。默认排除后,统计表中有两组多位置比对未分配。加入 -M -O --fraction 后,两处位置分别贡献半份,A 从二增加到二点五,C 从一增加到一点五。这个变化可以由输入中的两个位置和对应标签直接解释。

featureCounts -T 2 -R CORE -t exon -g gene_id \
  -a genes.gtf -o fractional.txt \
  -p --countReadPairs -M -O --fraction input.sam

这时统计表显示成功分配六组,而三个基因计数总和是五。原来有六个独立片段,其中一个没有落在注释区域,所以最终总贡献是五份。那个多位置片段在统计阶段对应两组被接受的比对,在权重阶段总共贡献一份。理解这一层关系,就不会把统计表的六误读为六个独立分子都被计入。

分摊得到的小数也不代表测到了半个物理分子,它是归属权重。这个规则没有像表达概率模型那样,依据不同转录本的丰度重新估计来源。因此,不能把这里的等权分摊与 RSEM 的期望计数视为同一种推断,也不能仅因为都出现小数就相互替换。

第四个对照,负链基因也能符合正向文库

链特异参数描述的是读段与转录方向的关系,并不是“只保留基因组正链基因”。我们专门放入负链基因 C,并让其第一端沿着基因的转录方向。正向链设置下,A、B、C 的片段计数仍为一、一、一,负链基因并没有被整体排除。

将参数改成反向链设置后,三个基因全部为零。统计表把原本可归属或重叠的片段转为没有符合条件的注释区域,多位置片段仍被归入多位置类别。这说明分类是经过一系列规则后的结果,不能把每个未分配类别都当成相互独立的生物学原因。

真实文库的链方向应来自建库方案并结合代表性数据核验。不能因为某个设置保留率更高就直接选它,更不能看到负链基因表达少,就把所有样本强行换成另一方向。对照实验只有在输入、注释和其他参数都不变时,才能帮助定位方向设置是否错误。

怎样把这次练习迁移到真实项目

首先写清计数单位,再固定注释版本和基因标识规则。准备进入批量计数前,应检查参考序列名称是否一致,尤其是染色体前缀、线粒体命名和附加序列。比对文件能正常打开,并不保证它与注释来自同一套参考。大量没有对应区域的读段可能来自这些不一致,也可能来自内含子、未注释转录或样本本身,不能只凭一个比例下结论。

然后分别检查比对位置与注释归属。多位置比例高,需要看重复序列和同源基因情况。歧义比例高,需要看重叠注释和计数层级。读对和链设置错误则可能让大量本来合理的片段失去归属。这几类问题对应不同证据,统一采用“放宽过滤”容易把结果推向无法解释的方向。

最后,把矩阵、分类统计、命令、版本和少量代表性归属记录一起保存。计数矩阵可以进入后续分析,但小数计数是否被下游方法接受,需要遵循该方法的输入要求。不能随意四舍五入后宣称恢复了真实整数计数,也不应把已经做过相对丰度归一化的数值混入原始计数矩阵。上下游之间最重要的接口,是每一列和每一个数的统计含义。

优点、限制和这次实跑经验

featureCounts 的优点是计数规则清楚,支持不同注释区域和多样本处理,分类统计及逐条归属能够帮助定位差异。它尤其适合在已知基因注释基础上构建表达计数矩阵。本次小实验也展示了它的可解释性,几个片段就能追溯最终数字的来源。

限制在于结果高度依赖比对、注释和规则选择。它不会替你补全缺失的转录本,也不会仅凭一个计数自动解决同源序列的来源问题。允许更多片段进入结果,意味着接受另一套归属假设,不能直接写成分析质量提高。阅读旧教程时还应核对本机帮助,因为版本演进可能改变某些选项的搭配要求。

这次最重要的经验,是先用极小输入验证规则,再扩展到大数据。七组结果中,除以二、要求所有统计求和相等、把负链基因等同于反向文库,这三种直觉都遇到了反例。把这些规则想清楚之后,读者面对一个复杂的真实矩阵,至少能够明确该追查哪份文件、哪类标签和哪一个参数。

下载本组复现脚本和实际输出。进一步核对参数可阅读 Subread 官方用户手册,方法背景见 featureCounts 原始论文。

当计数规则和样本质控已经明确,需要在一致环境中批量处理多个项目时,可了解云生信生物信息学分析服务器服务。

把知识用于当前任务

下一步可以直接开始分析

按研究目标查找在线工具、课程、计算资源或完整分析服务。

按目标找方案仍有疑问,联系客服 ↗