“ S3方法”在 R 中是什么意思?

由于我对 R 相当陌生,所以我不知道 S3方法和对象是什么。我发现有 S3和 S4对象系统,一些建议使用 S3超过 S4如果可能的话(见谷歌的 R 风格指南在 http://google-styleguide.googlecode.com/svn/trunk/google-r-style.html) * 。但是,我不知道 S3方法/对象的确切定义。

更新: 截至2019年,谷歌的 R 风格指南超链接现在是 给你

51627 次浏览

大多数相关信息可以通过查看 ?S3?UseMethod找到,但简而言之:

S3是一个方法调度方案。如果你使用 R 一段时间,你会注意到有 printpredictsummary方法为许多不同类型的对象。

在中三,这是通过以下方式实现的:

  • 设置对象的类 利息(例如: 对方法 glm的调用具有类 glm)
  • 提供一般的方法 名称(例如 print) ,然后一个点,和 然后是类名(例如: print.glm)
  • 肯定有些准备工作 做到这个一般名称(print) 但是如果你 只是为了让自己顺从 现有的方法名称,则不需要 这(见我提到的帮助 如果你早些时候这样做)。

对于魔眼杀机来说,特别是你新创建的时髦模型配件包的用户来说,输入 predict(myfit, type="class")比输入 predict.mykindoffit(myfit, type="class")要方便得多。

还有很多,但这应该可以让你开始。这种基于对象的属性(类)来调度方法的方法有很多缺点(纯 C 语言者可能会因为害怕而夜不能寐) ,但是在很多情况下,它工作得还不错。使用当前版本的 R,已经实现了更新的方法(S4和引用类) ,但是大多数人仍然(只)使用 S3。

要开始学习 S3,请查看 median函数的代码。在命令提示符下键入 median会显示它在主体中有一行,即

UseMethod("median")

这意味着它是一个 S3方法。换句话说,您可以为不同的 S3类使用不同的 median函数。要列出所有可能的中间方法,输入

methods(median) #actually not that interesting.

在这种情况下,只有一个方法,即默认方法,它是针对任何内容调用的。您可以通过输入

median.default

一个更有趣的例子是 print函数,它有许多不同的方法。

methods(print)  #very exciting

注意,有些方法的名称旁边有 *。这意味着它们隐藏在某个包的名称空间中。使用 find找出它们在哪个包中。比如说

find("acf")  #it's in the stats package
stats:::print.acf

试试看

methods(residuals)

其中包括“ restuals.lm”和“ restuals.glm”。这意味着当您已经拟合了线性模型 m 和类型 residuals(m)时,将调用 restuals.lm。当你安装了一个广义线性模式,残余物。 glm 将被称为。 这有点像把 C + + 对象模型颠倒过来。在 C + + 中,定义一个具有虚函数的基类,这些函数被派生的。 在 R 中,定义一个虚函数(又名泛型函数) ,然后决定哪些类将重写这个函数(又名定义一个方法)。请注意,执行此操作的类不需要从一个公共超类派生。 我不会同意一般喜欢 S3超过 S4。S4有更多的形式主义(= 更多的类型化) ,这对于某些应用程序来说可能太多了。然而,S4类可以像 C + + 中的类或结构一样进行反定义。您可以指定某个类的对象由一个字符串和两个数字组成,例如:

setClass("myClass", representation(label = "character", x = "numeric", y = "numeric"))

使用该类的对象调用的方法可以依赖于具有这些成员的对象。这与 S3类非常不同,S3类只是一组元素的列表。

对于 S3和 S4,可以通过 fun(object, args)而不是通过 object$fun(args)调用成员函数。如果您正在寻找类似于后者的东西,请看一下原型包。

我来到这个问题主要是想知道这些名字是从哪里来的。从 这篇维基百科的文章中可以看出,这个名称指的是 R 所基于的 S 编程语言的版本。其他答案所描述的方法调度方案来自 S,并根据版本进行了适当的标注。

来自 http://adv-r.had.co.nz/OO-essentials.html:

R 的三个面向对象系统在类和方法的定义方式上有所不同:

  • S3实现了一种称为泛型函数 OO 的面向对象编程风格。 这不同于大多数编程语言,如 Java、 C + + 和 C # ,它实现了消息传递 OO (方法)被发送到对象,对象决定哪个函数 通常,此对象在方法中具有特殊的外观 调用,通常出现在方法/消息的名称之前。 DraRect (“ blue”) . S3是不同的 通过方法执行,这是一种称为泛型的特殊类型的函数 函数决定调用哪个方法,例如 draRect (画布,“ blue”)。 S3是一个非常随意的系统,它没有类的正式定义

  • S4的工作方式与 S3类似,但更为正式 S4具有正式的类定义,这些类定义描述 每个类的表示和继承,并具有特殊的帮助器 定义泛型和方法的函数 分派,这意味着泛型函数可以基于 任意数量参数的类,而不仅仅是一个。

  • 引用类,简称 RC,与 S3非常不同 RC 实现了消息传递 OO,因此方法属于 $用于分隔对象和方法,因此 方法调用看起来像画布 $draRect (“蓝色”) Mutable: 它们不使用 R 通常的 copy-on-Amendment 语义,但是 这使他们更难推理,但允许 他们解决难以用 S3或 S4解决的问题

还有一个系统不是完全面向对象的,但它很重要 在此提及:

  • 基类型,即构成另一个 OO 的内部 C 级类型 基本类型大部分是用 C 代码操作的,但是它们 因为它们提供了 其他面向对象系统。

这里是根据 “高级 R,第二版”(CRC Press,2019)更新的众多 R 物体系统的快速纲要,由 Hadley Wickham (RStudio 的首席科学家)提供,它有一个基于关于 面向对象程序设计的章节的网络表示 给你

Advanced R book cover

2015年的第一版有一个网络表示 给你,对应的章节是 OO 给你

面向对象系统的实现方法

Hadley 定义了以下两种不同的面向对象编程方法:

Functional OOP : 方法(可调用代码段)属于 泛型函数(不要与 Java/C # 一般方法混淆)。可以将这些方法视为位于全局查找表中。要执行的方法由运行时系统根据函数的名称和传递给该函数的一个或多个参数的类型(或对象类)来找到(这称为“方法分派”)。从语法上看,方法调用可能与普通函数调用类似: myfunc(object, arg1, arg2)。这个调用将导致运行时查找与对 (“ myfunc”,typeof (object))关联的方法,如果语言支持这种方法,则可能是 (“ myfunc”,typeof (object) ,typeof (arg1) ,typeof (arg2))。在 R 的 S3中,泛型函数的全名给出了 (function-name,class)对。例如: mean.Date是计算日期平均值的方法。尝试 methods("mean")列出函数名为 mean的泛型方法。函数式面向对象方法可以在面向对象先驱 闲聊mean.Date0和 mean.Date1中找到。Hadley 指出,“与 R 相比,Julia 的实现是完全开发的,而且性能极佳。”

封装的 OOP : 方法属于对象或类,方法调用通常类似于 object.method(arg1, arg2)。这称为 封装好了,因为对象同时封装了 资料(字段)和 行为(方法)。可以将该方法视为位于附加到对象或对象的类描述的查找表中。运行库根据方法名以及可能的一个或多个参数的类型查找方法。这是在“流行的”面向对象语言(如 C + + 、 Java、 C #)中发现的方法。

在这两种情况下,如果支持继承(可能支持) ,运行时可以向上遍历类层次结构,直到找到与调用查找键匹配的类。

如何找出 R 对象属于哪个系统

library(sloop) # formerly, "pryr"
otype(mtcars)
#> [1] "S3"

R 物体系统

中三

  • 函数式面向对象方法。
  • 哈德利认为最重要的系统。
  • 最简单,最常见的。第一个面向对象系统使用 R。
  • 与基础 R 一起使用,整个基础 R。
  • 依靠公约而不是强制性保证。
  • 参见 约翰 · M · 钱伯斯和特雷弗 · J · 哈斯蒂.1992。《 S。统计模型》 ,沃兹沃斯和布鲁克斯/科尔高级图书和软件。
  • 详情请参阅 “高级 R,第二版”给你

中四

  • 函数式面向对象方法。
  • 哈德利认为第三重要的系统。
  • 重写 S3,因此类似于 S3,但是更加正式和严格: 它迫使您仔细考虑程序设计。适合于构建大型系统(例如 生物导体项目)。
  • 在基本“方法”包中实现。
  • 见: 数据编程: S 语言指南〉。
  • 详情请参阅 “高级 R,第二版”给你

RC 又名“参考课程”

  • 封装的 OOP 方法。
  • 是以 R 开头的。
  • 基于 S4。
  • RC 对象是 S4对象的特殊类型,也是“可变的”。也就是说,它们可以就地修改,而不是使用 R 的通常的“修改后拷贝”语义。请注意,可变状态是 很难解释和一个丑陋的错误来源,但可以导致更有效的代码在某些应用程序。

R6

  • 封装的 OOP 方法。
  • 哈德利认为第二重要的系统。
  • 可以在 R6包中找到(与 library(R6)一起安装)
  • 类似 RC,但更轻和更快: 它不依赖于 S4或 方法软件包。建立在 R 环境之上。还有:
    • 公共和私人方法
    • 活动绑定(字段,访问时实际调用方法)
    • 类继承,在包之间工作
    • 类方法(属于类的代码,可以通过 selfprivatesuper访问实例)和 成员函数成员函数(分配给字段的函数,但不是方法,只是函数)
  • 提供了一种标准化的方法来规避 R 的“复制-修改”语义
  • 查看包站点: “ R 6: R 的封装面向对象程序设计”
  • 详情请参阅 “高级 R,第二版”给你

其他人

还有其他的,像 (类似于 RC)、 原型(基于原型,想想 JavaScript)和 穆塔特。然而,“ Advanced R”说:

除了广泛使用的 R6之外,这些系统主要包括 他们确实有自己的优势,但是很少有 R 用户 认识和理解他们,所以对其他人来说很难阅读和 有助于您的代码。

也请务必阅读 “高级 R,第二版”中关于 权衡利弊的章节。