专栏首页生信菜鸟团读《R语言面向对象编程》

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

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

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

本文分享自微信公众号 - 生信菜鸟团(bio_123456789),作者:周运来

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-09-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 原 浅谈R语言的面向对象编程

    不高不富不帅的陈政_
  • R语言学习笔记——R语言面向对象编程系列2

    最近在看任坤大神的新作——《R语言编程指南》,其中对于编程语言中非常流行的面向对象编程范式(OOP)在R语言中的实现进行了非常详尽的讲解,强烈推荐各位有志于进阶...

    数据小磨坊
  • 「R」R 面向对象编程

    每一个单独的对象都可以被称为对应类的一个实例(instance)。操作指定类的函数称为方法(method)。

    王诗翔呀
  • Go语言与面向对象编程

    学习Go语言差不多快两个月了,感觉这个过程还是蛮快乐的,翻翻英文资料,写写小程序,总是觉得有好多东西都搞不明白,一步步走下来,却发现,这些迷惑好像也是不可或缺的...

    李海彬
  • Go语言与面向对象编程

    学习Go语言差不多快两个月了,感觉这个过程还是蛮快乐的,翻翻英文资料,写写小程序,总是觉得有好多东西都搞不明白,一步步走下来,却发现,这些迷惑好像也是不可或缺的...

    李海彬
  • R语言基础教程——第7章:面向对象编程(S3类)

    面向对象是一种对现实世界理解和抽象的方法,当代码复杂度增加难以维护的时候,面向对象就会显得非常重要。学过Java和Javascript两种语言的话,不难理解面向...

    DoubleHelix
  • R语言基础教程——第7章:面向对象编程(S4类)

    在S3对象中,一般我使用$来访问一个对象的属性,但在S4对象中,我们只能使用@来访问一个对象的属性

    DoubleHelix
  • Golang 语言是面向对象编程风格的编程语言吗?

    Golang 语言是面向对象语言吗?Golang 语言官方的回答是 Yes and no。什么意思呢?Golang 语言是面向对象语言,Golang 语言也不是...

    frank.
  • C语言到C++的OOP 面向对象编程

    1、全面兼容C,C的许多代码不经修改就可以为Cpp所用,用C编写的库函数和实用软件可以用于Cpp。

    小林C语言
  • C语言-结构体面向对象编程技巧

    一、面向对象 面向对象是软件开发方法,是相对于面向过程来讲的。通过把数据与方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式 单片机...

    好派笔记
  • 面向“对象”编程

    前面向对象和过面向都是一种思考方式也是一种思想的体现。面向过程是一种流程式的思考方式上一步不做,下一步便无法进行下去。

    DataScience
  • Go语言的面向对象

    go语言仅支持封装,不支持继承和多态。 go语言没有class,只有struct。

    JavaEdge
  • 面向对象的C语言

    大家在学C、C++ 的时候,老师多半会讲过:C语言是面向过程的编程语言,C++是面向对象的编程语言。但归根结底,面向过程还是面向对象,这是编程思想的差异,而不是...

    Seven Du
  • 趣味解读Python面向对象编程 (类和对象)

    考虑现实生活中,我们的思维方式是放在学生这个个人上,是学生做了自我介绍。而不是像我们刚刚写出的代码,先有了介绍的行为,再去看介绍了谁。

    前端皮皮
  • 一步步分析-C语言如何面向对象编程

    在嵌入式开发中,C/C++语言是使用最普及的,在C++11版本之前,它们的语法是比较相似的,只不过C++提供了面向对象的编程方式。

    IOT物联网小镇
  • Python面向对象编程

    张俊红
  • 面向对象编程-类

    面向对象编程OOP (object-oriented programming)是最有效的软件编写方法之一,面向对象是利用“类”和“对象”来创建各种模拟来实现对真...

    用户1679793
  • Python-面向对象编程

    概述: 面向过程:根据业务逻辑从上到下写代码。 函数式:将某功能代码封装到函数中,以后便无需重复编写,进调用函数即可。 面向对象:对函数进行分类和封装,让开发“...

    洗尽了浮华
  • Python面向对象编程

    面向对象最重要的概念就是类(Class)和实例(Instance),Java比较熟了,下面贴代码注释

    听着music睡

扫码关注云+社区

领取腾讯云代金券