“S3方法”在R中意味着什么?

问题描述 投票:105回答:5

由于我是R的新手,我不知道S3方法和对象是什么。我发现有S3和S4对象系统,如果可能的话,有些人建议使用S3而不是S4(http://google-styleguide.googlecode.com/svn/trunk/google-r-style.html)。但是,我不知道S3方法/对象的确切定义。

r r-faq r-s3
5个回答
76
投票

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

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

在S3中,这通过以下方式工作:

  • 设置感兴趣的对象类(例如:调用方法glm的返回值具有类glm
  • 提供一个带有通用名称的方法(例如print),然后是一个点,然后是类名(例如:print.glm
  • 为了实现这个目的,必须对这个通用名称(print)做一些准备工作,但是如果你只是想让自己符合现有的方法名称,那么你就不需要这个了(如果你的话,请参阅我之前提到的帮助)做)。

对于旁观者的眼睛,特别是新创建的时髦模型拟合包的用户,能够输入predict(myfit, type="class")predict.mykindoffit(myfit, type="class")更方便。

还有更多,但这应该让你开始。这种基于对象的属性(类)调度方法的方式存在很多缺点(而且纯粹主义者可能会在晚上醒来时很恐怖),但在很多情况下,它的工作正常。使用当前版本的R,已经实现了更新的方法(S4和参考类),但是大多数人仍然(仅)使用S3。


46
投票

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

UseMethod("median")

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

methods(median) #actually not that interesting.  

在这种情况下,只有一个方法,即默认值,可以调用任何方法。您可以通过键入来查看该代码

median.default

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

methods(print)  #very exciting

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

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

33
投票

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

R的三个OO系统在定义类和方法方面有所不同:

  • S3实现了一种称为泛型函数OO的OO编程风格。这与大多数编程语言不同,例如Java,C ++和C#,它们实现消息传递OO。通过消息传递,消息(方法)被发送到对象,对象确定要调用的函数。通常,此对象在方法调用中具有特殊外观,通常出现在方法/消息的名称之前:例如, canvas.drawRect( “蓝”)。 S3是不同的。虽然仍然通过方法执行计算,但是称为泛型函数的特殊类型的函数决定调用哪个方法,例如drawRect(canvas,“blue”)。 S3是一个非常随意的系统。它没有正式的类定义。
  • S4与S3的工作方式类似,但更为正式。 S3有两个主要的区别。 S4具有正式的类定义,它描述了每个类的表示和继承,并具有用于定义泛型和方法的特殊辅助函数。 S4也有多个调度,这意味着泛型函数可以根据任意数量的参数类来选择方法,而不仅仅是一个。
  • 参考类,简称RC,与S3和S4完全不同。 RC实现消息传递OO,因此方法属于类,而不是函数。 $用于分隔对象和方法,因此方法调用看起来像canvas $ drawRect(“blue”)。 RC对象也是可变的:它们不使用R的通常的复制修改语义,而是在适当的位置进行修改。这使得他们更难以推理,但允许他们解决难以用S3或S4解决的问题。

还有另外一个系统不是OO,但重要的是在这里提一下:

  • 基本类型,作为其他OO系统基础的内部C级类型。基本类型主要使用C代码进行操作,但它们很重要,因为它们为其他OO系统提供构建块。

11
投票

我来到这个问题,主要是想知道名字的来源。从this wikipedia article看来,该名称是指R所基于的S编程语言的版本。其他答案中描述的方法调度方案来自S,并根据版本进行适当标记。


7
投票

尝试

methods(residuals)

其中列出了“residuals.lm”和“residuals.glm”。这意味着当您拟合线性模型m和residuals(m)类型时,将调用residuals.lm。当您拟合广义线性模型时,将调用residuals.glm。这种C ++对象模型是颠倒的。在C ++中,您定义了一个具有虚函数的基类,这些函数被派生的类重写。在R中,您定义了一个虚拟(也称为通用)函数,然后您决定哪些类将覆盖此函数(也称为定义方法)。请注意,执行此操作的类不需要从一个公共超类派生。我不同意通常更喜欢S3而不是S4。 S4有更多的形式(=更多的打字),这对某些应用来说可能太多了。但是,S4类可以像C ++中的类或结构一样定义。您可以指定某个类的对象由字符串和两个数字组成,例如:

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.