跳到正文
百沐一下百沐一下
本节目录

基因 ID 转换:Symbol / Ensembl / Entrez

跟完这篇,您能分清 Symbol、Ensembl、Entrez 三类基因 ID 的关系,知道为什么建议用 Ensembl 当主键,并且会用几行代码把它们一键互转、把「一个基因占好几行」的重复规规矩矩地去掉。

基因 ID 转换是几乎每个分析都躲不开的一步:上游比对给的是 Ensembl,做 KEGG 富集又要 Entrez,出图给人看还得换回 Symbol。转来转去最容易出两类问题——转丢了一批转出来重名了。这篇就把这两件事讲透。

三类 ID 各是什么

同一个基因,在不同体系里有不同的「身份证号」。以人类的 TP53 为例:

类型长什么样特点谁在用
Gene SymbolTP53好记、给人看;会随版本更名、有别名、可能歧义论文、图表、人眼阅读
Ensembl IDENSG00000141510稳定、唯一,带版本号后缀;机器友好比对 / 定量输出、Ensembl 注释
Entrez ID(NCBI Gene ID)7157纯数字、稳定;不少工具默认要它KEGG 富集、NCBI 系工具

几点关系要记住:

  1. 三者是多对多映射,不是一一对应。一个 Symbol 可能对多个 Ensembl,一个 Ensembl 也可能对多个 Symbol。
  2. Ensembl ID 有物种前缀:人类基因是 ENSG,小鼠是 ENSMUSG;转录本另有 ENST / ENSMUST。别把基因层和转录本层的 ID 混用。
  3. Ensembl ID 常带版本号后缀(如 ENSG00000141510.11),小数点后的数字会随注释版本变化。转换前一般要先把它去掉,否则容易全部匹配不上(下面第三节讲)。

为什么建议用 Ensembl 当主键

存表达矩阵、做关联合并时,第一列(行名)用哪种 ID 当主键,直接决定后面顺不顺。建议是:用 Ensembl ID 当主键,Symbol 只作为一列人看的备注。

原因很直接:

对比项Gene SymbolEnsembl ID
是否唯一否,有别名、有历史名
是否稳定否,会随 HGNC 更新更名是,改名也保留旧 ID
机器可读性差,大小写 / 别名带来歧义好,无歧义
常见事故被 Excel 改成日期(见末节)基本不会

一句话:Symbol 是给人看的,Ensembl 是给机器认的。 拿会变、会重、会被表格软件悄悄改掉的 Symbol 当主键,是很多「样本 / 基因对不上」问题的根源。手头只有 Symbol 也能做分析,但更稳妥的做法是先转成 Ensembl 当主键。表达矩阵整理的整体规范见表达矩阵与分组表整理规范

转换前先去掉版本号

这是最容易被忽略、又最容易「全军覆没」的一步。带版本号的 Ensembl ID(ENSG00000141510.11)拿去和不带版本号的注释库匹配,会一个都对不上。先统一去掉:

# 去掉 Ensembl ID 的版本号后缀:ENSG00000141510.11 → ENSG00000141510
ids <- sub("\\.\\d+$", "", ids)

如果 ID 是表达矩阵的行名,就对行名做同样处理,顺手确认去版本号后没有产生重复:

rownames(counts) <- sub("\\.\\d+$", "", rownames(counts))
any(duplicated(rownames(counts)))   # 应为 FALSE,若为 TRUE 见「处理一对多」一节

一键互转:三种常用做法

三种做法各有适用场景,任选其一即可。前两种用本地注释包、快且离线;第三种走 Ensembl 服务器、字段最全。

做法一:clusterProfiler::bitr()——最省事,一次转多种。 适合手上是一串基因、想快速换个 ID 类型。

library(clusterProfiler)
library(org.Hs.eg.db)   # 人类注释库;小鼠换成 org.Mm.eg.db

# Symbol → Ensembl + Entrez,一次转两种目标类型
map <- bitr(c("TP53", "BRCA1", "KRAS"),
            fromType = "SYMBOL",
            toType   = c("ENSEMBL", "ENTREZID"),
            OrgDb    = org.Hs.eg.db)

注意 bitr() 默认会直接丢掉转不上的基因,并打印丢了多少。这个提示别忽略——丢失比例大时要回头查是不是物种选错、或该先去版本号。

做法二:AnnotationDbi::mapIds()——按向量原位对应,适合加一列注释。 它返回和输入等长、顺序对齐的结果,特别适合「给矩阵行名配一列 Symbol」。

library(AnnotationDbi)
library(org.Hs.eg.db)

sym <- mapIds(org.Hs.eg.db,
              keys      = rownames(counts),   # 一串 Ensembl ID(已去版本号)
              column    = "SYMBOL",           # 想要的目标类型
              keytype   = "ENSEMBL",          # 输入 ID 的类型
              multiVals = "first")            # 一对多时只取第一个(见下节)

做法三:biomaRt——字段最全,联网查 Ensembl。 适合要一次性拉齐 Ensembl、Symbol、Entrez、基因位置等多种字段。

library(biomaRt)

mart <- useEnsembl(biomart = "genes", dataset = "hsapiens_gene_ensembl")
map  <- getBM(attributes = c("ensembl_gene_id", "hgnc_symbol", "entrezgene_id"),
              filters    = "ensembl_gene_id",
              values     = ids,               # 输入的 Ensembl ID 向量
              mart       = mart)

三种做法的取舍:

做法依赖适合注意
bitr()本地 OrgDb快速换 ID 类型默认丢弃转不上的,看它打印的丢失数
mapIds()本地 OrgDb给矩阵配注释列一对多要指定 multiVals
biomaRt联网 Ensembl要多字段、要最新结果版本随 Ensembl 更新,注明版本

处理一对多与去重

ID 之间是多对多,转换后几乎一定会遇到两种「一对多」。规范做法如下:

情形会怎样规范做法
一个 Ensembl → 多个 Symbol一个 ID 配出好几个名字mapIdsmultiVals = "first" 取一个,但它是任取,重要基因请人工核对
多个 Ensembl → 一个 Symbol转 Symbol 后行名重复每个 Symbol 只保留表达最高的一行(惯例,非铁律)
转不上(结果为 NA假基因、废弃 ID、纯别名如实丢弃,并记录丢了多大比例

最推荐的做法其实是从源头绕开这个问题:主键始终用 Ensembl,Symbol 只当备注列,这样永远不会因为「换名字」而重复。只有确实需要以 Symbol 为行名(比如某些下游工具只认 Symbol)时,才需要下面这套按表达去重。它和整理矩阵时的去重是同一套逻辑:

library(dplyr)
library(org.Hs.eg.db)

expr2 <- counts %>%
  mutate(symbol = mapIds(org.Hs.eg.db, rownames(.),
                         "SYMBOL", "ENSEMBL", multiVals = "first"),
         .avg   = rowMeans(across(where(is.numeric)))) %>%   # 每行平均表达
  filter(!is.na(symbol)) %>%                                 # 丢掉没转上的
  arrange(desc(.avg)) %>%
  distinct(symbol, .keep_all = TRUE)                         # 每个 symbol 只留表达最高的一行

rownames(expr2) <- expr2$symbol
expr2 <- expr2 %>% select(-symbol, -.avg)
any(duplicated(rownames(expr2)))   # 应为 FALSE

「按表达最高保留」是被广泛采用的惯例,不是唯一正确答案——按数据和目的,也可换成对同名行求和取中位数(WGCNA 的 collapseRows() 就提供多种合并策略)。关键是方法要事先定好、全程一致,并在方法部分写清楚。

常见坑速查

最后这几条,踩中一个就可能悄悄把结果带偏:

  1. Excel 把基因名改成日期。 SEPT2MARCH1DEC1 这类 Symbol 会被 Excel 自动转成日期或数字,且往往不易察觉。HGNC 为此已给部分基因改名(如 MARCH1MARCHF1)。对策:用 Ensembl 当主键存表;确实要在表格软件里开含 Symbol 的文件时,先把该列设为文本格式。
  2. 物种选错。 人类用 org.Hs.eg.db、KEGG 代号 hsa;小鼠用 org.Mm.eg.dbmmu。人鼠 Symbol 大小写还不同(人 TP53 vs 鼠 Trp53),别直接套用。
  3. 版本号没去掉。.11 后缀去匹配注释库会几乎全丢,先做去版本号那一步。
  4. 注释库版本对不上数据。 您数据的注释版本和本地 OrgDb / biomaRt 的版本若差得远,老 ID 可能已废弃、转不上属正常;报告里注明所用注释版本。
  5. 丢失比例别不看。 无论 bitr() 还是 getBM() 都会丢一部分基因。留意丢了多少,比例偏高时先排查上面几条,必要时在正文说明。

在平台上跑一遍

百沐一下不写代码也能做这一步:把带任意一种 ID 的表格传上去,用一句话说清「把 Ensembl 转成 Symbol」或「转成 Entrez 做 KEGG 富集」,组学智能体会自动去版本号、按惯例去重、并把丢失比例告诉您,还给可复现的 R 代码。各类文件的 ID 与格式要求见上传数据的格式要求

相关