由于我对R相当陌生,所以我不知道S3方法和对象是什么。我发现有S3和S4对象系统,有些建议尽可能使用S3而不是S4(请参阅http://google-styleguide.googlecode.com/svn/trunk/google-r-style上的 Google R样式指南。 html)*。但是,我不知道S3方法/对象的确切定义。
更新:从2019年开始,Google的R样式指南超链接现在位于此处。
由于我对R相当陌生,所以我不知道S3方法和对象是什么。我发现有S3和S4对象系统,有些建议尽可能使用S3而不是S4(请参阅http://google-styleguide.googlecode.com/svn/trunk/google-r-style上的 Google R样式指南。 html)*。但是,我不知道S3方法/对象的确切定义。
更新:从2019年开始,Google的R样式指南超链接现在位于此处。
Answers:
通过查看?S3
或可以找到大多数相关信息?UseMethod
,但总而言之:
S3是指方法分派的方案。如果你使用的R用了一段时间,你会发现有print
,predict
并summary
进行了大量不同类型的对象的方法。
在S3中,此方法的工作原理是:
glm
具有class glm
)print
),则一个点,然后将类名(例如:
print.glm
)print
)进行一些准备才能使其正常工作,但是如果您只是想使自己符合现有的方法名称,则不需要这样做(请参阅我之前提到的帮助)。对于旁观者来说,尤其是对于您新创建的时髦模型拟合包的用户而言,键入predict(myfit, type="class")
比方便得多predict.mykindoffit(myfit, type="class")
。
还有很多其他功能,但这应该可以帮助您入门。这种基于对象的属性(类)的分派方法的方式有很多缺点(C纯粹主义者可能会在晚上惊恐地醒着),但是在很多情况下,它的工作方式相当不错。在当前版本的R中,已经实现了新的方式(S4和引用类),但是大多数人仍然(仅)使用S3。
要开始使用S3,请查看该median
功能的代码。median
在命令提示符下键入将显示其主体中有一行,即
UseMethod("median")
这意味着它是一种S3方法。换句话说,median
对于不同的S3类,您可以具有不同的功能。要列出所有可能的中位数方法,请键入
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
来自http://adv-r.had.co.nz/OO-essentials.html:
R的三个OO系统在定义类和方法的方式上有所不同:
S3实现了一种称为通用功能OO的OO编程风格。这与大多数实现消息传递OO的编程语言(例如Java,C ++和C#)不同。通过消息传递,消息(方法)被发送到对象,并且对象确定要调用的函数。通常,此对象在方法调用中具有特殊外观,通常出现在方法/消息名称之前:例如canvas.drawRect(“ blue”)。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系统提供了构建基块。
我问这个问题主要是想知道名字的来源。从该维基百科文章中可以看出,该名称是R所基于的S编程语言的版本。其他答案中描述的方法分配方案来自S,并根据版本进行适当标记。
尝试
methods(residuals)
其中列出了“ residuals.lm”和“ residuals.glm”。这意味着当您拟合线性模型,m和类型residuals(m)
,residentials.lm将被调用。拟合了广义线性模型后,将调用residentials.glm。有点像C ++对象模型倒挂了。在C ++中,您定义了具有虚函数的基类,这些虚函数被派生类覆盖。在R中,您定义一个虚拟(又称通用)函数,然后决定哪些类将覆盖此函数(即定义一个方法)。请注意,执行此操作的类不必从一个公共的超类派生。我不会同意通常更喜欢S3而不是S4。S4具有更多的形式主义(=更多类型),这对于某些应用程序可能太多了。但是,可以像C ++中的类或结构一样定义S4类。您可以指定某个类的对象由一个字符串和两个数字组成,例如:
setClass("myClass", representation(label = "character", x = "numeric", y = "numeric"))
用该类的对象调用的方法可以依赖于具有那些成员的对象。这与S3类非常不同,后者只是一堆元素的列表。
使用S3和S4,您可以通过fun(object, args)
而不是通过调用成员函数object$fun(args)
。如果您正在寻找类似后者的东西,请查看proto软件包。
这是根据Hadley Wickham(RStudio的首席科学家)的“ Advanced R,2nd edition”(CRC Press,2019年)更新的众多R对象系统的快速精简版本,此处基于有关对象的章节在此处具有Web表示形式面向程序设计。
Hadley定义以下内容以区分两种不同的面向对象编程方法:
功能性OOP:方法(可调用的代码段)属于泛型函数(请勿与Java / C#泛型方法混淆)。可以将这些方法视为位于全局查找表中。运行时系统根据函数的名称以及传递给该函数的一个或多个参数的类型(或对象类)来找到要执行的方法(称为“方法分派”)。在语法方面,方法调用可能看起来像普通的函数调用:myfunc(object, arg1, arg2)
。此调用将导致运行时查找与该对(“ myfunc”,typeof(object))或可能(“ myfunc”,typeof(object),typeof(arg1),typeof(arg2))关联的方法。如果语言支持。在R的S3中,泛型函数的全名给出了(函数名,类)对。例如:mean.Date
是计算日期均值的方法。尝试methods("mean")
使用函数名列出通用方法mean
。功能性OOP方法可在OO先驱Smalltalk,Common Lisp对象系统和Julia中找到。Hadley指出:“与R相比,Julia的实现是完全开发的并且性能极佳。”
封装的OOP:方法属于对象或类,方法调用通常看起来像object.method(arg1, arg2)
。之所以称为封装,是因为对象封装了数据(字段)和行为(方法)。可以将该方法视为位于附加到对象或对象的类说明的查找表中。运行时将根据方法名称以及一个或多个参数的类型来查找方法。这是在“流行的” OO语言(例如C ++,Java,C#)中发现的方法。
在两种情况下,如果都支持继承(可能是继承),则运行时可以向上遍历类层次结构,直到找到与调用查找键匹配的对象为止。
library(sloop) # formerly, "pryr"
otype(mtcars)
#> [1] "S3"
library(R6)
)self
,private
,super
)和成员函数(转让给字段的功能,但其不是方法,只是功能)还有其他一些,例如R.oo(类似于RC),proto(基于原型,例如JavaScript)和Mutatr。但是,“高级R”表示:
除了被广泛使用的R6之外,这些系统还主要具有理论意义。它们确实具有优势,但是很少有R用户了解和理解它们,因此其他人很难阅读并为您的代码做出贡献。
请务必阅读的章节的取舍在“高级R,第二版”了。