内容

1前言

1.1方法包裹

S4类系统在中实施方法包裹

成分:

  • 核心组件:通用功能方法

  • 胶:方法调度

S4类有时被称为正式课程

结果:丰富和复杂的系统(218个符号出口方法包裹)。可能会压倒。好消息是,我们只需要系统的一小部分。

1.2S4的优点(与S3相比)

1.2.1 "多次调度

1.2.2对象的验证

1.2.3API和内部

与其他OO编程语言不同,S4不提供封装的规定:内部对象的所有槽都是可见的,可以直接访问。然而,生物导体方法是考虑内部是开发人员的业务,最终用户应该永远不需要直接访问它们甚至看起来。访问只能通过访问器功能过时或者setter)。

这具有以下优点:

  • 开发人员在不破坏用户代码的情况下,可以自由修改对象的内部结构。

  • 精心制作的Serverer将确保对象在用户修改时保持有效。

  • 这种对象从外面看的分离,并且真正的内部允许开发人员在内部级别使用技巧来使对象更紧凑,以及更高效地制作更紧凑的物体。

所以从用户的角度来看,重要的是语义一个对象,即它代表什么以及它如何被操纵(API)。

即使是通过2021欧洲杯体育投注开户扩展现有类来实现新类的开发人员也应该以一种与他们所扩展的类的内部结构无关的方式来实现它。S4使这成为可能(这是一个很棒的功能)。稍后再详细介绍。

1.2.4强大的高压系统

1.2.5虚拟/具体类

一种虚拟的class是一个不能这样做的类促进。通常用作一个或多个具体课程的父母:

setClass(“A”,表示(“虚拟”))#虚拟类SetClass(“A1”,包含=“A”,Slots = ...某些插槽...)SetClass(“A2”,包含=“A”,插槽= ...一些其他插槽......)

例如,GRanges和GPos类都是虚拟类GenomicRanges的子类:

suppressPackageStartupMessages(库(GenomicRanges)) showClass(“GenomicRanges”)
##虚拟类别“genomicranges”[包“genomicranges”] ## ##插槽:## ##名称:ElementMetadata元数据##类:DataTable_or_Null列表## ##扩展:##类“Vector”,直接##类“genomicranges_or_missing”,直接##类“genomicranges_or_grangeslist”,直接##类“注释”,按类别“向量”,距离2 ## ##已知的子类:“Granges”,“GPOS”,“委派enomicranges”,“麦克兵”

许多方法可以以适用于2种对象的方式实现。

“名字”方法:

SelectMethod(“名称”,“Granges”)
##方法定义:## ## function (x) ## names(ranges(x)) ##  ## ##签名:## x ## target " grangies " ## defined "GenomicRanges"

也可以在GPos对象上工作,因为范围()getter作用于这些对象(和GRanges对象一样,它也返回一个names IRanges对象)。我们不定义2“名字”方法(一个用于GRanges对象,一个用于GPos对象)我们为GenomicRanges对象定义了一个方法。GRanges和GPos对象继承它。

1.2.6虚拟类没有插槽

虚拟类可以具有插槽(如GenomicRanges),或者没有插槽(如我们的第一个示例中的类)。通常,虚拟类的插槽不足以表示对象(这就是为本类的为什么虚拟)。具体子类添加丢失的插槽。

1.2.7多重继承

强大,但可以导致班级层次结构,如果没有仔细使用,很难维护。

showclass(“compressirangeslist”)
## Class "CompressedIRangesList" [package "IRanges"] ## ## Slots: ## ## Name: elementType elementMetadata metadata ## Class: character DataTable_OR_NULL list ## ## Name: unlistData partitioning ## Class: ANY PartitioningByEnd ## ## Extends:直接# # # #类“IRangesList”、“CompressedList”类,直接# #类“RangesList”,按类“IRangesList”,距离2 # #类“列表”,由“CompressedList”类,距离2 # #类“向量”,由“CompressedList”类,距离3 # #类“注释”,由“CompressedList”类,距离4 # # # #子类:“CompressedNormalIRangesList”

S4没有限制,但我认为我们从未有需要定义一个以上的直接父母的课程。

1.2.8团体

只是一种特殊的虚拟类,没有插槽。

showClass(“GenomicRanges_OR_GRangesList”)
##虚拟类“genomicranges_or_grangeslist”[包“genomicranges”] ## ##没有插槽,类“S4”###########类“Genomicranges”,直接##类“Grangeslist”,直接###课程“Granges”,按类别“Genomicranges”,距离2 ##类“GPO”,按类别“基因组织”,距离2 ##类“委派”,按类别的“Genomicranges”,距离2 ##级“麦克兵”,按类别的“基因组织”,距离2

(该类用于rangedsummarizeexperimental对象的定义。)

1.2.9引用类

很少需要。作为一般原则,R个物体应该有a通过副本语义因此,将它们传递给函数保证不修改原始对象。通过逐个参考语义几乎不需要,应该避免。

1.3第一个例子

打开快速概述S4等级系统(PDF)S4Vectors着陆页然后去实现S4类(在4个幻灯片中)部分。

锻炼

  • 实现snpllocations类(setClass()声明,有效方法,和“长度”仅限方法)。允许基因组槽含有na
SetClass(“Snprocations”,Slots = C(Genome =“字符”,#单个字符串或NA SNPID =“字符”,#长度n Chrom =“字符”的字符向量,#长度N POS =的字符向量“整数”#的整数矢量长度n))setvalidity(“snprocations”,函数(对象){if(length(对象@ genome)!= 1)返回(“'基因组插槽必须具有长度1”)slot_lengths <-  c(长度(对象@ snpid),长度(对象@ chrom),长度(对象@ pos))如果(长度(唯一(slot_lengths))!= 1)返回(“'snpid','chrom'和'pos'插槽必须具有相同的长度“)true})setmethod(”长度“,”snplocations“,函数(x)长度(x @ snpid))
  • 调用新(“SNPLocations”)。怎么了?这看起来对吗?

  • 我们怎样才能改变行为呢新(“SNPLocations”)所以它会生成一个有效的对象?

SetClass(“Snprocations”,Slots = C(Genome =“字符”,SnPID =“字符”,Chrom =“字符”,POS =“Integer”),Prototype = list(Genome = Na_character_))

2S4对象的设计与实现

2.1两种方法

  • 从头开始(罕见的情况)

  • 扩展现有类(减少工作)

2.2什么实施?

2.2.1核心的东西

  • 课程def(setClass陈述)

  • 有效性的方法

  • 构造函数(命名为类,应记录在案并便于用户使用)。

  • “秀”方法

2.2.2API.

至少有一些getter尝试重用现有的泛型,而不是引入新的泛型,例如:

  • 生物()分数()链()(定义为生物根系

  • 基因组()seqinfo ()(定义为Genomeinfodb.

取决于形状对象,用于以下某些核心通用功能的方法(从基础r):

  • 长度()名称()构造子集([[[),暗淡()dimnames ()C()

一些定居者(除非对象不打算被修改)

  • 对应getter的setter

  • 一些方法名字< -,子程序((< -[[< -),dimnames < -

专业的操作作为现有泛型的方法(例如。正常化定义生物根系),或作为新的泛型。

2.2.3胁迫方法

(snpid=from@snpid, chrom=from@chrom, pos=from@pos))

锻炼

从Snplocations实施胁迫方法到Granges。

2.3关于物体的形状

大多数物体属于其中一个类别

  • 矢量样式对象:长度()

示例:基础R的原子载体和普通名单;RLE,HITS,绞喉,古玩,格兰切斯列表,Dnastring,Dnastringset对象

  • 类似对象:矢量样式+[[

例如:base R. CharacterList, IRanges, IRangesList, GRangesList, Bioconductor中的DNAStringSet中的普通列表和数据帧。

  • 矩阵像类数组对象:暗淡()长度(x)(=刺激(暗(x))

示例:基础R中的矩阵和数组对象矩阵包中。对象中的DelayedArray对象DelayedArray包中。

  • 数据帧对象:暗淡()+类似在列

示例:BiConductor中基于R. DataFrame对象中的数据。

这些类别不互斥:

  • 列表类似的对象是矢量图上的对象

  • 阵列类似的对象也是载体样对象

  • 类数据帧对象是类列表对象:长度(x)ncol (x))名称(x)colnames (x)x[[我]]x [,i]它们不是类似矩阵的对象。

这些类别反映了形状对象

  • 线性形状:像矢量图,列表

  • 长方形形状:矩阵状,数据帧状,总结实验

  • 多维形状:数组类

矩形和多维物体具有“隐式线性形状”。将其视为物体的“骨干”。

例如,3种不同的线性形状可以与矩形形状相关联。它们由以下“骨干网”描述:

  1. “矩阵骨干”:

    从矩形的左上角元素运行到右下角元素,沿着所有列向下运行整个矩形(当到达一列的底部时,从下一列的顶部继续)

这是矩阵类对象的主干。类似数组的对象将其推广到N维:backbone首先沿着第一个维运行(在R中变化最快的维是第一个维),然后沿着第二个维运行,以此类推……

  1. “数据帧状骨干网”:

    运行水平从第一个到最后一列的矩形

这是数据帧样对象的骨干。

  1. Bioconductor介绍了第三种类型的骨干矩形对象:

    运行垂直从第一个到最后一行的矩形

这就是“总结的实验式脊梁”。

在实现表示矩形对象的类时,Developper应该决定对象的骨干链。具体地意味着决定什么“长度”方法将返回:刺激(暗(x))ncol(x), 或者nrow (x)吗?一旦做出这个选择,就像名称(x)x[我], 和C()应该始终如一(例如c (x, y)应该连接两个物体沿着他们的脊骨)。

使其清除骨干在文档中的内容将有助于用户理解(并预测)的行为长度(x)名称(x)x[我]C()等……

锻炼

Snplocations对象的形状是什么?

2.4构造子集

子集是R的强大且非常灵活的操作。

4子集运算符:[[[(< -[[< -

不同类型的子集:

  • 括号vs双括号
    • 括号[
    • 双支架[[(有时称为列表样式子集)。
  • 线性vs多维
    • 线性:仅使用1个下标:x[我]或者x[[我]]。有时叫1D式子集
    • 多维:使用超过1个下标:x [i_1,i_2,...,i_n]或者x [[i_1, i_2,…, i_n]]。一些(或全部)下标可以缺少例如x[, 3,]
  • 萃取vs替代品
    • 萃取y < - x[…]或者Y < - X [[...]]
    • 更换x [...] < - 值或者x[[…]] < -价值。子集是左边分配。价值被称为正确的价值或者替换价值。这种形式的子集呼叫(< -或者[[< -运营商。有时叫分配器

R语法允许这些类型的任意组合,例如:

  • Y < - X [I,J,K]:单括号多维子集

  • x [i] < - 值:单括号线性分配器

  • x [[i,j]] < - 值:双括号二维子程序

  • 等等……

==> 8可能的组合。

即使所有这些形式都是语法有效的,它们不一定对所有对象都有意义(在这种情况下,它们应该失败)。

对于支持它的多维对象,预期线性子集沿对象的骨干(1 <= i <= length(x))。

一些例子:

  • 普通矩阵,数组,数据帧,数据帧对象支持8种形式。问题:矩阵类对象和数据帧类对象的隐式线性形状不同,它们的线性子集也不同。

  • Summuarizedexperiment对象支持矩形(x (i, j))及线性(x[我])子集及其替换版本。x[我]x [i] < - 值相当于X [I,]x[i,] <- value,分别。问题:[[也得到支持但以非标方式行事!

  • 格兰人对象支持线性[(< -。为方便起见,还支持矩形子集(即使格子对象不是矩形的)。

锻炼

找到以R为基数进行子集设置的通用手册页。

找到子集数据帧的特定手册页。

看看签名[[[(< -, 和[[< -通用的功能。

锻炼

snpllocations对象自然会支持哪种形式的子集?

实施它。

2.5关于API设计

2.5.1一般性建议

避免令人惊讶的是。

特别注意如何如何如何长度()名称()[[[C()暗淡(), 和dimnames ()的行为。

还要注意两个被认为是好的属性的属性:

  • 转型是否正在实施保存位置?

  • 它应该表现得像一个自同态吗?

2.5.2改变保护位置性

当输出为平行也就是说,它与输入的长度相同,并且它的第i个元素对应于输入的第i个元素。

例子:

  • R基地的所有行动矢量化例如:

    • is.na ()重复()nchar ()Chartr()降低()grepl ()regexpr ()秩()

    • 从中的功能数学团体:日志()sqrt()cumsum (),…

    • 二元操作符:+-*/^==.<|,......相对于最长的操作数

    • 比赛()%, %(关于第一个参数)

  • SEQNAMES()开始()结束()宽度()链()Granges或Grangeslist对象上的吸气剂。

  • 内外范围的转换在Bioconductor如。转移()侧翼(),…

GR < -  GRANGES(C(“CHR1:51-70”,“CHR1:75-100”,“CHR1:6-55”))GR
##带有3个范围和0元数据列的Granges对象:## SEQNames范围股线##  <铁钢>  ## [1] CHR1 [51,70] * ## [2] CHR [75,100] * ## [3] CHR1 [6,55] * ## ------- ## SEQINFO:1来自未指定的基因组的序列;没有SEQLENG
Shift(GR,1000)
## GRANGES对象具有3个范围和0元数据列:## SEQNAMES范围范围股线##  <铁锯>  ## [1] CHR1 [1051,1070] * ## [2] CHR [1075,1100] * ## [3] CHR1 [1006,1055] * ## ------- ## SEQINFO:1来自未指定的基因组的序列;没有SEQLENG
  • Biostrings :: Translate()在dnastringset对象(不是在dnastring)上。

这些操作通常传播的名字。

当应用到Bioconductor对象时,还希望传播元数据列。

不要保留职位:

  • grep()sort ()命令()

  • 原子向量的总结函数,例如。min ()最大限度()和()吝啬的()刺激()全部()任何()然而,当应用于Bioconductor的数字列表或逻辑列表对象时,它们确实保留了位置性!

  • 设置操作e.g.联盟()相交(),…

  • 范围的转换在生物导体中(例如reduce ()分离()一般来说,不要保留职位性:

减少(gr)
## Granges对象具有2个范围和0元数据列:## SEQNAMES范围范围股线##  <铁锯>  ## [1] CHR1 [6,70] * ## [2] CHR [75,100] * ## ------- ## SEQINFO:1来自未指定的基因组的序列;没有SEQLENG

这些操作不会传播名称或元数据列。

锻炼

试一试独特的()sort ()命令()在numericlist,charactllist和rlelist对象上。

您如何提取唯一值对象吗?

计算大于给定值的数字列表对象中的值。

2.5.3成为或不成为子宫内术

一个子宫内骨膜是一种保留对象类的转换。

例子:

  • [(当drop = false.),除了阵列类似的对象上的线性子集

  • 替换方法:(< -[[< -和其他setter(例如。名字< -mcols < -seqinfo < -,…),但有一些明显的例外:

    • (< -当载体的存储器的存储器的原子矢量不能表示右值时(例如,X [2] < - 3.75在一个整数向量上,或x[2] < -“a”在数字矢量图中)

    • rowranges()在一个总结的实验实例上设置。

  • C()在线性对象上(例如Hits, GRanges, GRangesList, DNAStringSet对象等等),在因子上有一个明显的例外(这很糟糕!)

  • rbind()cbind()矩形对象

  • 内外范围的转换

不是子宫内膜:

  • C()在阵列类似的对象上

  • 范围的转换不是一般的自同态:

GPO < -  GPO(GR)GPO
## # GPos对象有96个位置和0个元数据列:## seqnames pos strand ##    ## [1] chr1 51 * ## [2] chr1 52 * ## [3] chr1 53 * ## [4] chr1 54 * ## [5] chr1 55 * ## # ... ... ... ...中国科学院上海生物技术研究所,上海生物技术研究所,上海生物技术研究所,上海生物技术研究所,上海生物技术研究所,上海生物技术研究所,上海生物技术研究所,上海生物技术研究所,上海生物技术研究所没有SEQLENG
减少(gpo)
## Granges对象具有2个范围和0元数据列:## SEQNAMES范围范围股线##  <铁锯>  ## [1] CHR1 [6,70] * ## [2] CHR [75,100] * ## ------- ## SEQINFO:1来自未指定的基因组的序列;没有SEQLENG
  • Biostrings :: Translate()

2.6重用现有课程

生物导体已经有一个适合您想要在您的包装中处理的数据的容器。

如果您的数据是矩形的,则首选将概括。

如果没有,那么也许通过添加几个插槽来扩展现有类是您需要执行的。

许多包已经通过总结实验做到了这一点,例如:

  • deseq2.使用DESeqDataSet和DESeqTransform容器

  • Minfi.使用MethylSet, RGChannelSet, RatioSet, GenomicMethylSet和GenomicRatioSet容器

  • VariantAnnotation.使用VCF类。

  • InteractionSet与互动仪容器。

  • 基因组夫妇随着基因组液容器。

  • SGSEQ.使用SGVariantCounts和sgfeatucounts容器。

  • 等位基因矛纪与ASESET,Riskvariant,Regions,Detectedai​​和LinkVariantalMLOF容器。

  • 还有很多…

问的Bioc-devel.如果您需要帮助找到正确的数据容器(按原样使用或扩展),可以使用邮件列表。

SummarizedExperiment小插图(可用这里)有一个专门用于如何扩展范围的ummarizeStiment类的部分。

从头开始开始新的课程应该是最后的手段。即使在这种情况下,也可能会扩展核心类层次结构底部的虚拟类之一。

例如:

  • 通过扩展带注释的类,您可以得到元数据()getter和setter都是现成的。

  • 通过扩展向量类(仅当您的对象是矢量样对象),您得到上面的(向量扩展注释),加上:
    • 长度()
    • mcols()框中的吸气剂和甲板
    • 的验证并行插槽几乎是开箱即用(通过a的定义“parallelslotnames”方法)
    • 自动子集的并行插槽如果您决定您的对象应该支持子集
  • 通过扩展列表类(仅当您的对象是列表的对象),您可以获得上面的所有(列表扩展向量),加上:
    • ElementType()几乎是开箱即用(通过在类定义中添加原型)
    • as.list ()
    • 访问有助于实现列表样式子集的机制([[[[< -)。

锻炼

  • 修改Snplocations类的定义以使其扩展向量。

  • 这样做是为了做到这一点?

2.7在不添加任何插槽的情况下扩展课程

有时,我们需要扩展一个类,而不是为它添加插槽,而是为对象添加约束。

例如,NormalIRanges对象和IRanges对象有相同的槽,但NormalIRanges对象有义务这样做正常的(见正常性部分isNormal ?这意味着什么)。

一个更简单的例子如下:假设我们想实现一个类,它代表恒定宽度的IRanges对象。一个简单的选择是扩展IRanges类:

SetClass(“ContanctWidthiranges”,包含=“陨石”)

并通过有效性方法添加“恒定宽度”约束:

setValidity("ConstantWidthIRanges", function(object) {w <- width(object) if (length(w) != 0L && any(w != w[[1]])) return("object width is not constant") TRUE})

(我们应该讨论长度(w)!= 0l && af(w!= w [[1]]vs长度(独特(w))> 1吗?)

S4系统提供了从父级到子级(提升)和从子级到父级(降级)的自动强制方法。

虽然有一个带有这些方法的Gotcha。

让我们来看看推广:

X < -  AS(绞喉(6:8,宽度= 10),“恒定脉络岩”)Y < -  AS(讽刺(6:8,END = 10),“恒壁三气氛”)

令人惊讶的是胁迫工作y但制作了一个无效的onlystwidthiranges对象:

ValidObject(x)#true validobject(y)#错误!

为什么?

让我们来看看降级:

x2 <- as(x, IRanges) y2 <- as(y, IRanges)

运行良好(两个对象都是有效的IRanges实例)。

因此,从IRanges到constant twidthirges的强迫被打破了。我们如何解决这个问题?

注意,还有其他用于实现恒定宽度的圆形物体的方法。

2.8覆盖现有的方法

当我们扩展一个类时,我们得到了许多开箱即用的东西(多亏了继承)。

几件事不如预期的那样工作,所以我们需要修复它们。这标准机制这样做是覆盖现有方法

在推翻方法时要记住的3重要事项:

  1. 我们只需要对行为不符合预期的方法这样做。

  2. 我们永远不应该覆盖一种改变其语义的方法!例如实现一个“宽度”rancesswidthiranges对象的方法,其作为单个数字返回宽度将是一个非常糟糕的想法。为什么?如果我们想要这样的话,我们该怎么办?

  3. 最后但并非最不重要的:有时我们这样做是为了提高性能!

例子:“和”compretingInteGerlist对象的方法。

2.9扩展VS组成

让我们说我们想实现一个类来表示一个数组上的视图,即一个数组上的多维窗口。窗口可以用一组范围来表示,每个维度一个范围,例如矩阵的顶角[1- 4,1 -5]。对于一个有N维的数组,我们需要N个范围来表示视图。我们将这种对象称为“视口”(与计算机图形学领域的术语类似)。

在我们的视口对象中,我们还希望存储“参考阵列”的尺寸即,在其中定义视口的阵列(A.k.a.“底层数组)。这将有助于验证目的。

考虑以下两种实现:

SetClass(“ArrayViewPort1”,包含=“Iranges”,表示(Refdim =“Integer”))SetClass(“ArrayViewPort2”,表示(Refdim =“Integer”,范围=“Iranges”))

一个延伸了讽刺类,所以继承讽刺插槽和完整的讽刺API。是(x,“IRanges”)对这些物体都是正确的。这表示:“一个ArrayViewport1对象燃气物体可以在预期的讽刺物体中使用任何地方“。

另一个使用组成。与ArrayViewPort1对象不同,ArrayViewPort2对象不是被认为是绞喉物体。但是他们其中一个内部(存储在'ranges'投币口)。

最后,2个容器存储相同的数据,但它们语义是不同的。哪一个选择?

现在,我想我的视口对象有一个数组的形状,即。暗淡()应该返回由视口划分的子数组的尺寸。我现在能做出正确的选择吗?

2.10记录S4类

  • 谈论访问器,而不是插槽。

  • 关注语义,而不是实现细节。

  • 如果您的类扩展了已经充分记录的类,请将读取器引用到该类的手册页并添加链接(通常在\也可以看看部分)。不要在手册页中重复这些信息。

  • 添加{MyClass} \别名(此外\别名{class:myclass}{MyClass-class} \别名),使最终用户更容易找到您的手册页。

gpo ?在里面GenomicRanges以包为例。

3.解剖标题对象

图书馆(DelayedArray)
##加载所需包:MatrixStats
## ##附加包:'DelayedArray'
##以下对象从“包:matrixstats”屏蔽:## ## Colmax,科尔姆斯,Colranges,Rowmax,Rowmins,Rowranges
##以下对象从“包:基础”屏蔽:## ##申请
网格< -  ArrayRegularGrid(C(10L,10L),间隔= C(5L,4L))网格
## 2 x 3 ArrayRegularGrid对象在10 x 10阵列上:## [,1] [,2] [,3] ##] [1-5,1-4] [1-5,5-8] [1-5,9-10] ## [2,] [6-10,1-4] [6-10,5-8] [6-10,9-10]

4.资源

5.确认

本课程中报告的研究得到了国家人类基因组研究所和国家癌症研究所的奖励号码U41HG004059和U24CA180996的国家癌症研究所。

该项目已收到欧洲联盟Horizo​​ n 2020研究和创新计划下的欧洲研究委员会(ERC)的资金(Grant协议号633974)