Reference builds、contig 命名与 Liftover:如何避免“坐标正确但装配错误“的基因组陷阱
2026/9/10 13:11:21 网站建设 项目流程

Reference builds、contig 命名与 Liftover:如何避免"坐标正确但装配错误"的基因组陷阱

【免费下载链接】scientific-agent-skillsTurn any AI agent into an AI Scientist. The #1 Agent Skills library for science, used by 190,000+ scientists worldwide. 165 ready-to-use validated skills plus 100+ scientific databases covering biology, chemistry, medicine, and drug discovery. Compatible with Cursor, Claude Code, Codex, Pi, Antigravity, and the open Agent Skills standard.项目地址: https://gitcode.com/GitHub_Trending/cl/scientific-agent-skills

在基因组学中,一个坐标脱离了它所测量的参考装配(reference assembly)就毫无意义。两个文件可能共享 contig 名称、共享坐标范围、干净地 join 在一起,却指向基因组的完全不同的区域——这是最安静、也最危险的一类基因组学 bug。本文以 scientific-agent-skills 仓库中 genomic-coordinates 技能的 reference-builds.md 为骨架,结合其配套工具 check_contigs.py 的源码实现与测试用例,系统讲解 GRCh37/hg19、GRCh38/hg38、T2T-CHM13v2.0 三大参考装配的判别方法、GRCh37 与 hg19 的线粒体差异、b37 家族、GRCh38 的 ALT contig、四种 contig 命名方案以及 liftover 的失败模式。读完你将能:用一段命令识别任意文件的装配与命名风格、在任何跨装配 join 之前预先发现不兼容,并在报告中正确记录坐标的装配归属。

装配判别:长度即指纹

坐标本身不携带装配信息。判断一个文件属于哪个装配,最可靠的信号是主染色体的长度——三大参考装配的主染色体长度各不相同,构成一组天然的"指纹"。

以下长度表取自 UCSCbigZipschrom.sizes,并对照 NCBI 的 GRCh37.p13 装配报告交叉验证(2026-07-26 校验)。同一张表内嵌在scripts/check_contigs.pyBUILDS字典中(见 check_contigs.py),用于将文件与装配进行匹配:

ContigGRCh37 / hg19GRCh38 / hg38T2T-CHM13v2.0 / hs1
chr1249,250,621248,956,422248,387,328
chr2243,199,373242,193,529242,696,752
chrX155,270,560156,040,895154,259,566
chrY59,373,56657,227,41562,460,029
chrM / MT16,571(hg19)/ 16,569(GRCh37)16,56916,569

注意 chrM 一行是特例:hg19 的线粒体是 16,571 bp,而 GRCh37 与 GRCh38 都是 16,569 bp。这意味着 chrM 长度只用于区分 hg19 与其它装配,无法区分 GRCh37 与 GRCh38。

在源码中,这条判别逻辑体现为identify()函数:它将观测到的 contig 长度折叠(canonical_contig)后,与BUILDS中的三个候选装配逐一比对,按"匹配的主染色体比例"打分取最高分;若主染色体长度匹配率低于 90% 则判定为 unknown;若存在长度冲突则返回CONFLICT。而MITO字典(check_contigs.py)进一步用线粒体长度分辨 hg19(16,571 bp,UCSC NC_001807)与 GRCh37/38(16,569 bp,rCRS MT)。

对区间文件(BED/GTF/VCF),identifyexact=False模式工作:因为区间文件中的数字是"观测到的最大坐标"而非 contig 长度,此时只问"坐标是否溢出候选装配",避免把数字更小误判为长度冲突。测试 test_scripts.py 中test_bed_max_coordinate_is_not_treated_as_a_contig_lengthtest_bed_past_the_contig_end_is_caught分别验证了这两种情况。

实际使用非常简单:

cd skills/genomic-coordinates/scripts python3 check_contigs.py --identify unknown.fa.fai

输出示例(来自 SKILL.md):

file kind contigs naming assembly detail ref.fa.fai sizes 25 plain GRCh37 24/24 primary chromosome lengths match; chrM is 16569 bp, i.e. GRCh37/38 (rCRS MT)

check_contigs.py可以读取.fai.chrom.sizes、VCF 头(##contig行,回退到 CHROM 列的最大 POS)、SAM 头(@SQ行)、FASTA、BED 与 GTF/GFF(见load()函数,check_contigs.py),并报告任何会导致 join 出错的原因:命名不一致、长度冲突、坐标越过 contig 末端、仅存在于单侧文件的 contig。任何不兼容时退出码为 1,可用作 CI 门禁。

GRCh37 不是 hg19:只差一个线粒体

对每条主染色体而言,GRCh37 与 hg19 是同一个装配,唯一的例外是线粒体:

  • UCSC 的 hg19 保留了旧的NC_001807序列,16,571 bp
  • GRCh37 采用了修订后的剑桥参考序列(rCRS,NC_012920),16,569 bp
  • GRCh38 同样使用 rCRS。

因此在识别时,chrM 长度把 hg19 与其它一切装配区分开来,但无法区分 GRCh37 与 GRCh38(它们长度相同)。源码注释与MITO字典对此有明确说明(check_contigs.py):hg19 = UCSC NC_001807 chrM (16,571),GRCh37/38 = rCRS MT (16,569)。

这一差别的后果是灾难性的隐蔽:

  • 每个线粒体坐标在 hg19 BAM 与 GRCh37 VCF 之间都不同。核基因组坐标完全相同,所以整个流程正常运行,只有 mtDNA 结果出错——这是最难察觉的那类错误。
  • 基于 hg19 做出的线粒体异质性与单倍群(haplogroup)判定,无法与任何 rCRS 体系的结果比较,除非重新判定。

除了线粒体长度,两者的命名与交替单倍型处理也不同:

GRCh37 (Ensembl/NCBI)hg19 (UCSC)
常染色体1,2, …chr1,chr2, …
线粒体MT(16,569)chrM(16,571)
交替单倍型GL000250.1风格9 条chr6_cox_hap2风格 contig
未定位GL000191.1风格chrUn_gl000191

测试套件用真实 fixture 验证了这一点:test_hg19_is_identified_by_its_mitochondrion断言 hg19 的chrom.sizes被识别为hg19且 detail 中包含16571test_grch37_is_identified_by_its_mitochondrion断言GRCh37.fa.fai被识别为GRCh37且命名风格为plain;而test_grch37_and_hg19_are_reported_as_incompatible验证当 GRCh37 文件与 hg19 文件同时传入时,脚本报出naming differs16569并返回退出码 1(见 test_scripts.py)。

b37 家族

b37(Broad 命名)是采用简洁命名与 rCRSMT的 GRCh37。hs37d5(1000 Genomes phase 2)则是 b37 加上一条诱饵 contig(hs37d5)与 EBV 基因组。

三者的主坐标完全一致,因此可以通过重命名 contig相互转换,无需 liftover。但有一个隐蔽的副作用:在hs37d5中比对到诱饵 contig 的 reads,在 b37 中会比对到主装配的某个位置,这会在受影响区域改变覆盖度与变异判定——即使坐标系根本没有移动。

GRCh38 与它的 ALT contig

UCSC 发布的 hg38 包含25 条主 contig、261 条_altcontig、42 条_random和 127 条chrUn_。ALT contig 是那些真正存在多态性的区域(主要是 MHC 与 HLA 单倍型)的替代表示。

它们以一种特定的方式破坏朴素分析:来自 ALT 区域的 read 可以同等地比对到主 contig 和其 ALT contig,因此两种比对都被标记为MAPQ 0,而任何带 MAPQ 过滤的变异判定器都会整个丢弃该区域——覆盖度图上 MHC 所在位置出现一个"洞"。

通常的两种修复方案:

  • No-ALT 分析集——移除 ALT contig 后的主装配。这是最简单的选项,也是正确的默认选择,除非你确实需要 HLA 分型。
  • ALT-aware 比对——bwa-mem配合.alt文件与bwa-postalt.js,将 ALT 比对提升回主 contig。

分析集还会对 chrY 上的拟常染色体区域(PAR)做硬掩蔽,使 PAR reads 比对到 chrX 而不是分散到两者。掩蔽不改变 contig 长度,因此check_contigs.py仍会把掩蔽后的分析集识别为 GRCh38——掩蔽在 contig 表中不可见,只能通过检查序列来确认。这正是"长度是必要不充分的判别信号"的又一实例。

补丁版本(GRCh38.p13p14)会新增_fix和新的_altcontig,但绝不会移动主染色体上的坐标。p13 的坐标就是 p14 的坐标。

T2T-CHM13:一个真正不同的装配

CHM13v2.0 不是补丁,而是一个真正不同的装配:每个坐标都不同,并且它新增了 GRCh38 中完全没有坐标的序列(着丝粒卫星阵列、近端着丝粒短臂)。对于这些新解析的区域不存在干净的 liftover——因为根本没有可"lift to"的目标。当前绝大多数公开注释、绝大多数临床变异数据库、绝大多数已发表坐标仍然是 GRCh38 的。

因此实际工作流中,T2T-CHM13 更适合作为发现新序列区域的研究参考,而非日常分析的主装配。在切换到 T2T 之前,务必确认你的下游工具、注释源与临床数据库是否支持它。

Contig 命名:同一染色体,四种写法

当前流通着四种指向同一染色体的命名方案:

chr1 UCSC 1 Ensembl, NCBI, GATK b37 NC_000001.11 RefSeq accession (GRCh38);NC_000001.10 是 GRCh37 CM000663.2 GenBank accession (GRCh38);CM000663.1 是 GRCh37

关键点:承载装配信息的是 accession 的版本后缀,而不是基础 accessionNC_000001.10NC_000001.11只差最后一个字符,却是两个不同的装配。在 check_contigs.py 中,naming_style()函数(check_contigs.py)通过NC/NT/NW/GL/KI/CM/GCA/GCF_前缀识别 accession 风格,通过chr前缀比例区分chr-prefixedplainmixedcanonical_contig()则把chr1/1chrM/MT/chrMT折叠到同一键上用于跨文件比较(但绝不会写回数据文件)。

重命名是修复手段,bcftools annotate --rename-chrssamtools reheader以及一个两列的映射文件都能完成。两条规则必须遵守:

  1. 重命名更小、更便宜的那个文件,并把它的命名改成与参考一致——永远不要重命名参考
  2. chrMMT只在GRCh37 与 GRCh38 家族文件之间是一个"重命名";在 hg19 与任何 rCRS 体系之间它是一个谎言,因为序列本身不同。

跨命名方案的 join不会报错。它只是返回恰好匹配的那些行——常常是零行,偶尔当一个文件被部分重命名时返回一个误导性的子集。这正是compare()函数(check_contigs.py)要拦截的问题:它会报告两个文件的命名风格差异("naming differs between files... rename one side first")、共享 contig 上的长度冲突("these are different assemblies and their coordinates are not comparable")、单侧越界,以及"某文件中 N 条 contig 在另一文件中缺失(大多数工具会静默丢弃这些记录)"。而check_contigs.py会报告每个文件的命名风格,并在两个文件不一致时拒绝判定为兼容——测试test_grch37_and_hg19_are_reported_as_incompatible验证了这一行为。

Liftover:近似工具与五类失败模式

liftOver(UCSC,配合.chain文件)与CrossMap(额外支持 BAM、VCF 与 BigWig)是实际可用的工具。两者本质都是近似操作:

  • 坐标可能消失。新装配中删除的区域没有目标。liftOver 会把这些坐标写入 unmapped 文件——这个文件很容易被忽略,每次都应该统计它的行数
  • 映射可能一对多。在目标装配中重复的区域会映射到多个位置;取第一个是一种无声的选择。
  • 链方向可能翻转。不同装配之间的倒位区段意味着正链特征被 lift 到负链。区间文件可以承受这一点;任何序列方向敏感的东西(引物位点、guide RNA、motif 命中)都不能。
  • 区间端点可能独立提升。一个长特征可能被 lift 成不同长度,或者被拆开。
  • 变异需要的远不止坐标。VCF 被 lift 之后,REF可能不再匹配新参考;如果区段发生倒位,REFALT需要反向互补。CrossMap vcf处理这一点,纯坐标式 lift 不处理。之后必须对目标参考重新运行normalize_variant.py,并统计MISMATCH行数。

lift 两次——37 → 38 → 37——并不能可靠地回到原始坐标。当原始数据可以针对目标装配重新处理时,那比任何 liftover 都更准确。这一原则在技能的 variant-representation.md 中有完整的呼应:左对齐(left-align)需要读取参考序列,交给错误的装配会得到"自信而错误"的答案,因此REF字段会先与 FASTA 核对,不匹配即停止该记录——REFmismatch 是最廉价的装配不匹配探测器。

装配检查的一体化工作流

将本技能的全部工具串成一条流水线(参见 SKILL.md 与 variant-representation.md 的推荐流程):

cd skills/genomic-coordinates/scripts # 1. 两个文件是否同装配、同命名? python3 check_contigs.py setA.vcf setB.vcf --genome ref.fa.fai # 2. 结构约定是否完好? python3 audit_intervals.py setA.vcf --genome ref.fa.fai # 3. 拆分、核对 REF、修剪、左对齐——两组都用同一参考 python3 normalize_variant.py --fasta ref.fa --split --input setA.vcf -o A.norm.tsv python3 normalize_variant.py --fasta ref.fa --split --input setB.vcf -o B.norm.tsv

只有在完成第 3 步之后,才应该按CHROM:POS:REF:ALT进行 join。在第 3 步之前计算的交集是"未知规模的低估",而且是有偏的:它系统性低估重复区中的 indel——而那里正是大多数有趣变异所在。

记录什么:坐标必须随身携带装配

结果表、图形或补充文件中的坐标,都应该在数字旁边写明装配。"chr7:5,530,601-5,530,625" 不是一个位置;"chr7:5,530,601-5,530,625 (GRCh38)" 才是。这也正是整个 genomic-coordinates 技能的根本规则:一个坐标是三个事实而非一个——数字本身、书写它的约定(0-based/1-based、半开/闭区间)、以及测量它的装配。三者缺一,数字就不可解释。

  • 坐标列的约定(0-based 还是 1-based)应写进列名或文件文档;
  • 一次转换产生了结果,就应说明转换的方向;
  • 跨装配的任何操作,先运行check_contigs.py,再谈坐标。

总结

  • 长度是装配的指纹BUILDS表内嵌于 check_contigs.py,一行命令即可识别任意文件的装配与命名风格;
  • GRCh37 ≠ hg19:唯一差别是线粒体(16,569 vs 16,571 bp),却足以让 mtDNA 结果整体出错且毫无报错;
  • b37 家族靠重命名互转,但诱饵 contig 的存在会悄悄改变覆盖度与变异判定;
  • GRCh38 的 261 条 ALT contig会在 MHC 区域制造 MAPQ 0 空洞,No-ALT 分析集是最安全的默认;
  • 命名方案有四种写法,重命名时只改小文件、且chrMMT绝不能跨 hg19/rCRS 边界;
  • liftover 有五类失败模式,务必统计 unmapped、处理一对多、倒位、端点分裂与 REF 不匹配;
  • 记录坐标时永远标注装配

配套的 check_contigs.py、normalize_variant.py、audit_intervals.py 与其测试 test_scripts.py 全部只依赖 Python 标准库、离线运行,可作为你个人流程或 CI 门禁的直接组件。

【免费下载链接】scientific-agent-skillsTurn any AI agent into an AI Scientist. The #1 Agent Skills library for science, used by 190,000+ scientists worldwide. 165 ready-to-use validated skills plus 100+ scientific databases covering biology, chemistry, medicine, and drug discovery. Compatible with Cursor, Claude Code, Codex, Pi, Antigravity, and the open Agent Skills standard.项目地址: https://gitcode.com/GitHub_Trending/cl/scientific-agent-skills

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询