R中的“S3方法”是什么意思?
由于我对R相当陌生,我不知道S3方法和对象是什么。 我发现有S3和S4对象系统,有些人build议尽可能使用S4以上的S3(http://google-styleguide.googlecode.com/svn/trunk/google-r-style.html)。 但是,我不知道S3方法/对象的确切定义。
大部分相关信息可以通过查看?S3
或?UseMethod
,但简而言之:
S3是指调度方法。 如果你已经使用了R一段时间,你会注意到有很多不同types的对象都有print
, predict
和summary
方法。
在S3中,这个工作方式是:
- 设置感兴趣对象的类(例如:
glm
方法调用的返回值有glm
类) - 提供一个通用的名称(例如
print
),然后是一个点,然后是类名(例如:print.glm
) - 为了这个工作,一些准备工作已经完成了这个通用名称(
print
),但是如果你只是想要符合现有的方法名称,你不需要(请参阅我之前提到的帮助,如果你做)。
对于旁观者,特别是新创build的时髦模型拟合软件包的用户来说,能够predict(myfit, type="class")
比predict.mykindoffit(myfit, type="class")
。
还有更多,但这应该让你开始。 这种基于对象的属性(class)的调度方法有很多缺点(C纯粹主义者可能在夜里惊慌失措),但是在很多情况下,它的工作是体面的。 使用当前版本的R,已经实现了更新的方法(S4和参考类),但是大多数人仍然(仅)使用S3。
为了让您开始使用S3,请查看median
函数的代码。 在命令提示符下键入median
,可以发现它的正文中有一行,即
UseMethod("median")
这意味着这是一个S3方法。 换句话说,对于不同的S3类你可以有不同的median
函数。 要列出所有可能的中位数方法,请input
methods(median) #actually not that interesting.
在这种情况下,只有一个方法,即默认值,这被称为任何东西。 你可以通过键入查看代码
median.default
一个更有趣的例子是print
function,它有许多不同的方法。
methods(print) #very exciting
请注意,其中一些方法的名称旁边有*
。 这意味着它们隐藏在某个包的名称空间内。 使用find
来找出它们在哪个包中。例如
find("acf") #it's in the stats package stats:::print.acf
从http://adv-r.had.co.nz/OO-essentials.html :
R的三个面向对象系统在定义类和方法方面有所不同:
S3实现了一种称为通用函数OO的OO编程风格。 这与大多数实现消息传递OO的编程语言(如Java,C ++和C#)不同。 通过消息传递,消息(方法)被发送给对象,对象决定调用哪个函数。 通常,这个对象在方法调用中有一个特殊的外观,通常出现在方法/消息的名字之前:例如canvas.drawRect(“blue”)。 S3是不同的。 虽然计算仍然通过方法执行,但是一种称为generics函数的特殊函数决定调用哪种方法,例如drawRect(canvas,“blue”)。 S3是一个非常随意的系统。 它没有正式的类定义。
S4与S3类似,但更为正式。 S3有两个主要的区别。 S4具有正式的类定义,描述每个类的表示和inheritance,并且具有用于定义generics和方法的特殊帮助函数。 S4也有多个调度,这意味着generics函数可以根据任意数量的参数类来select方法,而不仅仅是一个。
简称为RC的参考类与S3和S4完全不同。 RC实现消息传递OO,所以方法属于类而不是函数。 $用于分隔对象和方法,所以方法调用看起来像canvas $ drawRect(“blue”)。 RC对象也是可变的:它们不使用R的通常的copy-on-modify语义,但是被修改了。 这使得他们更难以推理,而是让他们解决S3或S4难以解决的问题。
还有一个其他的系统不是很OO,但是在这里提一下很重要:
- 基础types,作为其他面向对象系统基础的内部C级types。 基本types大多使用C代码来操作,但是它们很重要,因为它们为其他面向对象系统提供了构build块。
我来到这个问题,主要是想知道名字来自哪里。 从这个维基百科文章看来, 这个名字是指R所基于的S编程语言的版本。 其他答案中描述的方法调度scheme来自S并根据版本进行适当的标记。
尝试
methods(residuals)
其中列出了“residuals.lm”和“residuals.glm”。 这意味着当你拟合了一个线性模型m和typesresiduals(m)
,residuals.lm将被调用。 当你拟合了一个广义线性模型时,residuals.glm将被调用。 这是一种颠倒的C ++对象模型。 在C ++中,你定义了一个具有虚函数的基类,它被派生分类覆盖。 在R中你定义了一个虚拟(又名通用)函数,然后你决定哪个类将会覆盖这个函数(又名定义一个方法)。 请注意,这样做的类不需要从一个普通的超类派生。 我不同意一般比S3更喜欢S3。 S4有更多的forms主义(=更多的打字),这可能是一些应用程序太多。 但是,S4类可以像C ++中的类或结构一样定义。 您可以指定某个类的对象由一个string和两个数字组成,例如:
setClass("myClass", representation(label = "character", x = "numeric", y = "numeric"))
用该类的对象调用的方法可以依赖于具有这些成员的对象。 这与S3类非常不同,它们只是一系列元素的列表。
使用S3和S4,你可以通过fun(object, args)
而不是object$fun(args)
调用成员函数。 如果你正在寻找类似于后者的东西,看看proto软件包。