由于我对R很新,我不知道S3方法和对象是什么。我发现有S3和S4对象系统,如果可能的话,有些人建议使用S3而不是S4(http://google-styleguide.googlecode.com/svn/trunk/google-r-style.html)。但是,我不知道S3方法/对象的确切定义。
答案 0 :(得分:76)
查看?S3
或?UseMethod
可以找到大部分相关信息,但简而言之:
S3指的是方法调度方案。如果您已经使用了R一段时间,您会发现有很多不同类型的对象有print
,predict
和summary
方法。
在S3中,这适用于:
glm
的调用具有类glm
)print
),然后是一个点,和
然后是类名(例如:
print.glm
)print
)
为了这个工作,但如果你是
只是想让自己顺从
现有的方法名称,您不需要
这(请参阅我提到的帮助
如果你这样做,那就更早了。)对于旁观者,尤其是新创建的时髦模型拟合包的用户而言,能够键入predict(myfit, type="class")
比predict.mykindoffit(myfit, type="class")
更方便。
还有更多内容,但这应该让你开始。这种基于对象的属性(类)调度方法的方式存在很多缺点(而且纯粹主义者可能会在晚上醒来时很恐怖),但在很多情况下,它的工作正常。使用当前版本的R,已经实现了更新的方法(S4和参考类),但大多数人仍然(仅)使用S3。
答案 1 :(得分:46)
要开始使用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
答案 2 :(得分:33)
来自http://adv-r.had.co.nz/OO-essentials.html:
R的三个OO系统在定义类和方法方面有所不同:
S3实现了一种称为泛型函数OO的OO编程风格。 这与大多数编程语言不同,如Java,C ++和 C#,实现消息传递OO。通过消息传递,消息 (方法)被发送到对象,对象确定哪个函数 打电话。通常,此对象在方法中具有特殊外观 呼叫,通常出现在方法/消息的名称之前:例如 canvas.drawRect("蓝色&#34)。 S3是不同的。虽然计算仍在进行中 通过方法执行,一种称为泛型的特殊类型的函数 函数决定调用哪个方法,例如drawRect(canvas," blue")。 S3是一个非常随意的系统。它没有正式的类定义。
S4的工作方式与S3相似,但更为正式。主要有两个 与S3的差异。 S4有正式的类定义,用来描述 每个类的表示和继承,并有特殊的帮助 用于定义泛型和方法的函数。 S4也有多个 dispatch,这意味着泛型函数可以选择基于的方法 任意数量的参数的类,而不仅仅是一个。
简称为RC的引用类与S3完全不同 和S4。 RC实现消息传递OO,因此方法属于 课程,而不是功能。 $用于分隔对象和方法,所以 方法调用看起来像canvas $ drawRect(" blue")。 RC对象也是 可变:他们不使用R的通常的复制修改语义,但是 修改到位。这使他们更难以推理,但允许 它们用于解决S3或S4难以解决的问题。
另外还有一个系统不是OO,但它很重要 在这里提一下:
- 基类型,构成另一个OO的内部C级类型 系统。基本类型主要使用C代码进行操作,但它们是 重要的是要知道因为它们提供了构建块 其他OO系统。
答案 3 :(得分:11)
我来到这个问题,主要是想知道名字的来源。从this wikipedia article看来,该名称是指R所基于的S编程语言的版本。其他答案中描述的方法调度方案来自S,并根据版本进行适当标记。
答案 4 :(得分: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)
调用成员函数。如果您正在寻找类似后者的东西,请查看原型包。
答案 5 :(得分:0)
这里是根据Hadley Wickham(首席科学家)的“ Advanced R,第二版” (CRC出版社,2019年)更新的众多 R对象系统的快速精简版本。 (在RStudio中),基于关于here的章节,其网络表示为Object-Oriented Programming。
2015年的第一版具有网络表示形式here,并在OO here上有相应的章节。
Hadley定义以下内容来区分两种不同的面向对象编程方法:
功能性OOP :方法(可调用的代码段)属于 generic functions (不要与Java / C#generic methods混淆)。可以将这些方法视为位于全局查找表中。运行时系统根据函数的名称以及传递给该函数的一个或多个参数的类型(或对象类)来找到要执行的方法(称为“方法分派”)。就语法而言,方法调用可能看起来像普通的函数调用:myfunc(object, arg1, arg2)
。此调用将导致运行时查找与(“ myfunc”,typeof(object))对关联的方法,或者可能与(“ myfunc”,typeof(object),typeof(arg1)相关联的方法。 ),typeof(arg2))(如果语言支持)。在R的S3中,泛型函数的全名给出(函数名,类)对。例如:mean.Date
是计算日期均值的方法。尝试使用methods("mean")
列出功能名称为mean
的通用方法。例如,在OO先锋Smalltalk,Common Lisp Object System和Julia中可以找到功能性OOP方法。 Hadley指出“与R相比,Julia的实现是完全开发的,并且性能极佳。”
封装的OOP :方法属于对象或类,并且方法调用通常看起来像object.method(arg1, arg2)
。之所以称为 encapsulated ,是因为对象同时封装了 data (字段)和 behaviour (方法)。可以将该方法视为位于对象或对象的类说明所附的查找表中。运行时会根据方法名称以及一个或多个参数的类型来查找方法。这是在“流行”的OO语言(例如C ++,Java,C#)中发现的方法。
在两种情况下,如果都支持继承(可能是继承),则运行时可以向上遍历类层次结构,直到找到与调用查找键匹配的对象为止。
library(sloop) # formerly, "pryr"
otype(mtcars)
#> [1] "S3"
library(R6)
一起安装)中找到self
,private
,super
访问实例的代码)和成员函数< / em>(分配给字段的函数,但不是方法,而只是函数)还有其他名称,例如 R.oo (类似于RC), proto (基于原型,使用JavaScript)和 Mutatr 。但是,“高级R”表示:
除了被广泛使用的R6,这些系统主要是 理论兴趣。他们确实有长处,但R用户很少 了解并理解它们,因此他人难以阅读和理解 为您的代码做出贡献。
也请务必阅读“ Advanced R,第二版” 中的trade-offs章节。