如何给Seurat对象的基因重命名?【基因名转换】2022-07-27

适用背景

在单细胞分析中,必要的一步是对每个细胞进行注释,这相当于给每个细胞打个标签,或者说起个别名,这些信息都存在@meta.data信息里,所以不用特意去更改细胞名字,Seurat官网也有相关教程进行这些步骤。但是,如果想改基因名字该怎么改呢?

为什么要改基因名字?常用的基因名一般是字母+数字的基因Symbol形式,例如GAD1和FLT1等等,但有时候拿到的矩阵基因名是类似ENS*这种以基因ID的形式命名基因的,这对于后续分析来说不太方便,毕竟大多数研究是直接使用基因Symbol,因此转换后会更好分析和理解。另外,在做跨物种分析时,我们需要进行跨物种的数据整合分析,这个时候就需要进行同源基因转换,然后使用同源基因集去做整合聚类,因此也需要把基因名字进行重命名,例如小鼠抑制性神经元的经典marker基因是Gad1,而人与其同源的基因是GAD1,如果以人作为参考,则需要把小鼠的基因也改成GAD1,类似的,小鼠里的所有能与人同源的基因都需要做这种转换,之后才能同时把人和小鼠的表达矩阵进行整合分析。

怎么改Seurat的基因名?当然,最简单的方法是导出矩阵,对矩阵的基因名进行替换即可,然后用替换后的矩阵再创建Seurat对象,这是比较简单粗暴也是比较容易理解的办法。此外,另一个解决方法是把Seurat对象里所有涉及基因名的地方都进行基因名转换,本文就是基于此想法写了个函数。

注意:使用本篇的内容,建议使用DietSeurat函数尽量精简Seurat对象之后再改基因名,不然可能会有很多的bugs。


函数灵感来源

然而,官网目前并没有现成的函数对Seurat对象进行基因重命名。GitHub上的一个 issue 倒是有解决方案,然而只对obj@assays$RNA@counts, @data and @scale.data这些改了基因名,实测在运行某些函数,例如FindVariableFeatures时就会报错。

事实上,这个函数主要就是对Seurat对象里的各种需要用到基因名的地方进行了基因转换,以下是原始代码:

RenameGenesSeurat <- function(obj = ls.Seurat[[i]], newnames = HGNC.updated[[i]]$Suggested.Symbol) { # Replace gene names in different slots of a Seurat object. Run this before integration. Run this before integration. It only changes obj@assays$RNA@counts, @data and @scale.data.
  print("Run this before integration. It only changes obj@assays$RNA@counts, @data and @scale.data.")
  RNA <- obj@assays$RNA

  if (nrow(RNA) == length(newnames)) {
    if (length(RNA@counts)) RNA@counts@Dimnames[[1]]            <- newnames
    if (length(RNA@data)) RNA@data@Dimnames[[1]]                <- newnames
    if (length(RNA@scale.data)) RNA@scale.data@Dimnames[[1]]    <- newnames
  } else {"Unequal gene sets: nrow(RNA) != nrow(newnames)"}
  obj@assays$RNA <- RNA
  return(obj)
}

但是这个代码只改变了RNA的assays,而且如果修改的assay不是RNA而是integrated的话,修改scale.data那一步会容易报错,这个函数虽然简单也容易理解,但是就是不好用,改完之后的Seurat对象在运行很多函数时都会报错。

升级版函数 RenameGenesSeurat_v2

由于原来的函数太过简单,局限性太多而且,而且有不少bugs,所以基于它的版本我做了一些改进,然后封装成函数RenameGenesSeurat_v2

  • obj,Seurat对象
  • newnames,新的基因名字集向量,与gene.use的基因集一一对应
  • gene.use,使用的基因集向量,默认使用所有原始基因,如果给定基因集会对obj取基因子集,长度需与newnames一样,并且与newnames对应
  • de.assay,默认的assay,单细胞数据填RNA,空间组数据填Spatial
RenameGenesSeurat_v2 <- function(obj,newnames,gene.use=NULL,de.assay="RNA") {
print("Run this before integration. It only changes obj@assays$*@counts, @data and @scale.data, @var.features,@reductions$pca@feature.loadings")
lassays <- Assays(obj)
assay.use <- obj@reductions$pca@assay.used
DefaultAssay(obj) <- de.assay
if (is.null(gene.use)) {
all_genenames <- rownames(obj)
}else{
all_genenames <- gene.use
obj <- subset(obj,features=gene.use)
}

order_name <- function(v1,v2,ref){
v2 <- make.names(v2,unique=T)
df1 <- data.frame(v1,v2)
rownames(df1) <- df1$v1
df1 <- df1[ref,]
return(df1)
}

df1 <- order_name(v1=all_genenames,v2=newnames,ref=rownames(obj))
all_genenames <- df1$v1
newnames <- df1$v2

if ('SCT' %in% lassays) {
if ('SCTModel.list' %in%  slotNames(obj@assays$SCT)) {
obj@assays$SCT@SCTModel.list$model1@feature.attributes <- obj@assays$SCT@SCTModel.list$model1@feature.attributes[all_genenames,]
rownames(obj@assays$SCT@SCTModel.list$model1@feature.attributes) <- newnames
}
}
change_assay <- function(a1=de.assay,obj,newnames=NULL,all_genenames=NULL){
RNA <- obj@assays[a1][[1]]
  if (nrow(RNA) == length(newnames)) {
    if (length(RNA@counts)) RNA@counts@Dimnames[[1]]            <- newnames
    if (length(RNA@data)) RNA@data@Dimnames[[1]]                <- newnames
    if (length(RNA@var.features)) {
        df1 <- order_name(v1=all_genenames,v2=newnames,ref=RNA@var.features)
        all_genenames1 <- df1$v1
        newnames1 <- df1$v2
        RNA@var.features            <- newnames1
    }
    if (length(RNA@scale.data)){
        df1 <- order_name(v1=all_genenames,v2=newnames,ref=rownames(RNA@scale.data))
        all_genenames1 <- df1$v1
        newnames1 <- df1$v2
        rownames(RNA@scale.data)    <- newnames1
    }

  } else {"Unequal gene sets: nrow(RNA) != nrow(newnames)"}
  obj@assays[a1][[1]] <- RNA
  return(obj)
}

for (a in lassays) {
DefaultAssay(obj) <- a
df1 <- order_name(v1=all_genenames,v2=newnames,ref=rownames(obj))
all_genenames1 <- df1$v1
newnames1 <- df1$v2
obj <- change_assay(obj=obj,a1=a,newnames=newnames1,all_genenames=all_genenames1)
}

hvg <- VariableFeatures(obj,assay=assay.use)
if (length(obj@reductions$pca)){
    df1 <- order_name(v1=all_genenames,v2=newnames,ref=hvg)
    all_genenames1 <- df1$v1
    newnames1 <- df1$v2
    rownames(obj@reductions$pca@feature.loadings) <- newnames1
}

return(obj)
}

这个函数不仅仅对单个assay进行基因名转换,而是会对所有的assay都进行转换,另外还会对obj@reductions$pca@feature.loadings进行转换,这个处理会使得FindVariableFeatures正常运行。另外对于做了SCTransform的含有SCT assay的Seurat对象,还转换了obj@assays$SCT@SCTModel.list$model1@feature.attributes。

  • 使用示例
ingene <- read.table('gene_human.xls',sep='\t',header=T,stringsAsFactor=F)
ob3 <- RenameGenesSeurat(obj=ob3,newnames=ingene$hs_gene,gene.use=ingene$Axolotl_ID)

更新20230519

RenameGenesSeurat <- function(obj,newnames,gene.use=NULL,de.assay="Spatial") {
  # Replace gene names in different slots of a Seurat object. Run this before integration. Run this before integration.
  # It only changes obj@assays$RNA@counts, @data and @scale.data.
print("Run this before integration. It only changes obj@assays$*@counts, @data and @scale.data, @var.features,@reductions$pca@feature.loadings")
lassays <- Assays(obj)
#names(obj@assays)
assay.use <- obj@reductions$pca@assay.used
DefaultAssay(obj) <- de.assay
if (is.null(gene.use)) {
all_genenames <- rownames(obj)
}else{
all_genenames <- gene.use
obj <- subset(obj,features=gene.use)
}

order_name <- function(v1,v2,ref){
v2 <- make.names(v2,unique=T)
df1 <- data.frame(v1,v2)
rownames(df1) <- df1$v1
df1 <- df1[ref,]
return(df1)
}

df1 <- order_name(v1=all_genenames,v2=newnames,ref=rownames(obj))
all_genenames <- df1$v1
newnames <- df1$v2

if ('SCT' %in% lassays) {
if ('SCTModel.list' %in%  slotNames(obj@assays$SCT)) {
obj@assays$SCT@SCTModel.list$model1@feature.attributes <- obj@assays$SCT@SCTModel.list$model1@feature.attributes[all_genenames,]
rownames(obj@assays$SCT@SCTModel.list$model1@feature.attributes) <- newnames
}
}
change_assay <- function(a1=de.assay,obj,newnames=NULL,all_genenames=NULL){
RNA <- obj@assays[a1][[1]]
  if (nrow(RNA) == length(newnames)) {
    if (length(RNA@counts)) RNA@counts@Dimnames[[1]]            <- newnames
    if (length(RNA@data)) RNA@data@Dimnames[[1]]                <- newnames
    if (length(RNA@var.features)) {
        df1 <- order_name(v1=all_genenames,v2=newnames,ref=RNA@var.features)
        all_genenames1 <- df1$v1
        newnames1 <- df1$v2
        RNA@var.features            <- newnames1
    }
    if (length(RNA@scale.data)){
        df1 <- order_name(v1=all_genenames,v2=newnames,ref=rownames(RNA@scale.data))
        all_genenames1 <- df1$v1
        newnames1 <- df1$v2
        rownames(RNA@scale.data)    <- newnames1
    }

  } else {"Unequal gene sets: nrow(RNA) != nrow(newnames)"}
  obj@assays[a1][[1]] <- RNA
  return(obj)
}

for (a in lassays) {
DefaultAssay(obj) <- a
df1 <- order_name(v1=all_genenames,v2=newnames,ref=rownames(obj))
all_genenames1 <- df1$v1
newnames1 <- df1$v2
obj <- change_assay(obj=obj,a1=a,newnames=newnames1,all_genenames=all_genenames1)
}
hvg <- VariableFeatures(obj,assay=assay.use)
if (length(obj@reductions$pca)){
    df1 <- order_name(v1=all_genenames,v2=newnames,ref=hvg)
    df1 <- df1[rownames(obj@reductions$pca@feature.loadings),]
    all_genenames1 <- df1$v1
    newnames1 <- df1$v2
    rownames(obj@reductions$pca@feature.loadings) <- newnames1
}
try(obj[[de.assay]]@meta.features <- data.frame(row.names = rownames(obj[[de.assay]])))
return(obj)
}

小结与讨论

以上函数适用于已经完成聚类分析的Seurat对象,也就是含有pca,umap等降维信息的对象,如果是什么都没做,完全就是一个新的只载入矩阵的Seurat对象,建议还是直接对矩阵操作更方便快捷。
目前用这个RenameGenesSeurat_v2函数还没发现什么问题,可能还要遗漏需要改基因名的地方,欢迎评论区补充!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容