前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >读《R语言面向对象编程》

读《R语言面向对象编程》

作者头像
生信菜鸟团
发布2021-09-17 14:23:55
1.6K0
发布2021-09-17 14:23:55
举报
文章被收录于专栏:生信菜鸟团生信菜鸟团

跟着运来兄搭建自己的生物信息小书房。趁年轻,读几本硬书,到老了慢慢反刍。

R主要面向统计计算,为数据科学家青睐,代码量一般不会很大,使用面向过程的编程方式就可以很好的完成编程任务。而且还是有RStudio这样的交互操作集成开发环境,所以大部分的R语言用户对R语言是不是面向对象很是疑惑,虽然我们都知道在R中一切皆对象,比如Seurat对象。

其实用过Seurat的话,会感受到它既有S3 面向对象结构,又有S4对象结构。阅读源码也验证了这一点:其实Seurat这个R包用的主要是S3面向对象结构,但是在创建数据对象的时候用的是S4类。如下:

Seurat <- setClass(
  Class = 'Seurat',
  slots = c(
    assays = 'list',
    meta.data = 'data.frame',
    active.assay = 'character',
    active.ident = 'factor',
    graphs = 'list',
    neighbors = 'list',
    reductions = 'list',
    images = 'list',
    project.name = 'character',
    misc = 'list',
    version = 'package_version',
    commands = 'list',
    tools = 'list'
  )
)

那么,R语言中的面向对象到底是怎样的呢?这个问题需要答案。面向对象对很多程序员来说都不陌生,不管是真的会用还是讲笑话的时候听过。在提到这个名词的时候总是和一些听不懂的词汇联系到一起,如抽象,封装,继承,多态等。但是面向对象却是写给人看的。在面向对象的程序设计中,对象(object)是最基本的元素,不过对象指的是具体的实例,在对象之上还有一个类(class)的概念。

在R语言的中文世界里,R语言面向对象编程的知识很少被提及,大部分的R语言书籍是偏应用的。有的话也散见于《R语言核心技术手册》《高级R语言编程指南》《R语言编程艺术》等,很少有专门来讲这一节的。这与R语言的用户大多不是程序员不无关系,也与R语言的面向对象结构发展曲折有一定关系。在R中有四种面向对象结构。

但是正当我们苦于没有系统的R语言面向对象资料的时候,我们发现了这本在线书:R语言面向对象编程。里面有对这四种类型的详细介绍,而且还有可执行的实例代码,这无疑会加快一般用户对R语言面向对象的理解。

这本书并不厚,代码也很简单,我们就不再这里一一演示了。就着Seurat的对象结构,我们来演示S3和S4的实现,这为我们理解Seurat的源码也是有所裨益的。

  • S3方法
zgetEMB3 <- function(object,ebm='pca',...) UseMethod("zgetEMB3")
zgetEMB3.Seurat<- function(object,ebm='pca',...){
  (object@reductions[[ebm]]@cell.embeddings[,1:2])
}

> head(zgetEMB3(pbmc_small,ebm = 'tsne'))
                    tSNE_1      tSNE_2
ATGCCAGAACGACT   0.8675977  -8.1007483
CATGGCCTGTGCAT  -7.3925306  -8.7717451
GAACCTGATGAACC -28.2064258   0.2410102
TGACTGGATTCTCA  16.3480689 -11.1633255
AGTCAGACTGCACA   1.9113998 -11.1929311
TCTGATACACGTGT   3.1475998  -9.9369312
> head(zgetEMB3.Seurat(pbmc_small))
                      PC_1       PC_2
ATGCCAGAACGACT -0.77403708 -0.8996461
CATGGCCTGTGCAT -0.02602702 -0.3466795
GAACCTGATGAACC -0.45650250  0.1795811
TGACTGGATTCTCA -0.81163243 -1.3795340
AGTCAGACTGCACA -0.77403708 -0.8996461
TCTGATACACGTGT -0.77403708 -0.8996461
> showMethods(zgetEMB3)

Function "zgetEMB3":
 <not an S4 generic function>
> getMethod("zgetEMB3","Seurat")
Error in getMethod("zgetEMB3", "Seurat") : 
  no generic function found for 'zgetEMB3'
> getS3method("zgetEMB3","Seurat")
function(object,ebm='pca',...){
  (object@reductions[[ebm]]@cell.embeddings[,1:2])
}
<bytecode: 0x00000196ab91f060>
> ftype(zgetEMB3)
[1] "s3"      "generic"
> otype(zgetEMB3)
[1] "base"
> 
  • S4 方法
setGeneric("zgetEMB4",function(obj,...){
  standardGeneric("zgetEMB4")
})
setMethod("zgetEMB4","Seurat",function(obj,ebm='pca',...){
  (obj@reductions[[ebm]]@cell.embeddings[,1:2])
  
})
> head( zgetEMB4(pbmc_small,'tsne'))
                    tSNE_1      tSNE_2
ATGCCAGAACGACT   0.8675977  -8.1007483
CATGGCCTGTGCAT  -7.3925306  -8.7717451
GAACCTGATGAACC -28.2064258   0.2410102
TGACTGGATTCTCA  16.3480689 -11.1633255
AGTCAGACTGCACA   1.9113998 -11.1929311
TCTGATACACGTGT   3.1475998  -9.9369312
> head(zgetEMB4(pbmc_small,'pca'))
                      PC_1       PC_2
ATGCCAGAACGACT -0.77403708 -0.8996461
CATGGCCTGTGCAT -0.02602702 -0.3466795
GAACCTGATGAACC -0.45650250  0.1795811
TGACTGGATTCTCA -0.81163243 -1.3795340
AGTCAGACTGCACA -0.77403708 -0.8996461
TCTGATACACGTGT -0.77403708 -0.8996461
> head(zgetEMB4(pbmc_small))
                      PC_1       PC_2
ATGCCAGAACGACT -0.77403708 -0.8996461
CATGGCCTGTGCAT -0.02602702 -0.3466795
GAACCTGATGAACC -0.45650250  0.1795811
TGACTGGATTCTCA -0.81163243 -1.3795340
AGTCAGACTGCACA -0.77403708 -0.8996461
TCTGATACACGTGT -0.77403708 -0.8996461
> getMethod("zgetEMB4","Seurat")
Method Definition:

function (obj, ...) 
{
    .local <- function (obj, ebm = "pca", ...) 
    {
        (obj@reductions[[ebm]]@cell.embeddings[, 1:2])
    }
    .local(obj, ...)
}
<bytecode: 0x00000196abc3d068>

Signatures:
        obj     
target  "Seurat"
defined "Seurat"
> getS3method("zgetEMB4","Seurat")
Error in getS3method("zgetEMB4", "Seurat") : 
  no function 'zgetEMB4' could be found
In addition: Warning message:
In findGeneric(f, envir) :
  'zgetEMB4' is a formal generic function; S3 methods will not likely be found
> showMethods(zgetEMB4)
Function: zgetEMB4 (package .GlobalEnv)
obj="Seurat"

> ftype(zgetEMB4)
[1] "function"
> otype(zgetEMB4)     
[1] "S4"

查看目前Seurat的方法:

methods(class="Seurat")
 [1] $                             $<-                           [                             [[                           
 [5] [[<-                          AddMetaData                   as.CellDataSet                as.loom                      
 [9] as.SingleCellExperiment       Command                       DefaultAssay                  DefaultAssay<-               
[13] dim                           dimnames                      droplevels                    Embeddings                   
[17] FindClusters                  FindMarkers                   FindNeighbors                 FindSpatiallyVariableFeatures
[21] FindVariableFeatures          GetAssay                      GetAssayData                  GetImage                     
[25] GetTissueCoordinates          HVFInfo                       Idents                        Idents<-                     
[29] Key                           levels                        levels<-                      Loadings                     
[33] merge                         Misc                          Misc<-                        names                        
[37] NormalizeData                 OldWhichCells                 Project                       Project<-                    
[41] RenameCells                   RenameIdents                  ReorderIdent                  RunALRA                      
[45] RunCCA                        RunICA                        RunLSI                        RunPCA                       
[49] RunTSNE                       RunUMAP                       ScaleData                     ScoreJackStraw               
[53] SetAssayData                  SetIdent                      show                          SpatiallyVariableFeatures    
[57] StashIdent                    Stdev                         subset                        SubsetData                   
[61] SVFInfo                       Tool                          Tool<-                        VariableFeatures             
[65] VariableFeatures<-            WhichCells                    zgetEMB3                      zgetEMB4                     
see '?methods' for accessing help and source code

可以看到我们创建的 zgetEMB3 和 zgetEMB4 已经在其中了。S4对象系统具有明显的结构化特征,更适合面向对象的程序设计。S3对象简单,具有动态性,结构化特征不明显,S4对象结构化,功能强大。Seurat 目前的结构是结合这两者,但是开发者文档写的很清楚:作者是建议使用S3的。而Bioconductor社区以S4对象作为基础框架,只接受S4定义的R包。这也某种程度上解释了为什么我们从来不没有在Bioconductor上安装过Seurat。loomR是基于R6面向对象类型实现的。

另外,在读Seurat源码的时候我们发现了下面的语法,作为思考题:这两种函数定义的方式有什么不同,说说其中的缘由。

#' @rdname DefaultAssay
#' @export
#' @method DefaultAssay Assay
#'
DefaultAssay.Assay <- function(object, ...) {
  object <- UpdateSlots(object = object)
  return(slot(object = object, name = 'assay.orig'))
}
#' @export
#' @method DefaultAssay<- Assay
#'
"DefaultAssay<-.Assay" <- function(object, ..., value) {
  object <- UpdateSlots(object = object)
  return(slot(object = object, name = 'assay.used'))
  object <- UpdateSlots(object = object)
  slot(object = object, name = 'assay.orig') <- value
  return(object)
}

在线电子书地址,见所附第一条链接


https://dataxujing.github.io/R_oop/index.html

https://github.com/satijalab/seurat/wiki/S3-methods

https://github.com/satijalab/seurat/issues/990

https://www.tutorialspoint.com/r/r_functions.htm

https://adv-r.hadley.nz/functions.html

https://stat.ethz.ch/R-manual/R-patched/library/methods/html/Methods_for_S3.html

https://satijalab.org/loomR/loomR_tutorial.html

https://satijalab.org/seurat/install.html

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-09-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 生信菜鸟团 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档