R是一个基于使用泛型函数的面向对象的编辑语言。每个对象有一个类属性,这个类属性决定当对象的副本传递到类似于print(), plot()和summary()这些泛型函数时运行函数时运行什么代码。
R有两个分离的面向对象编程的模型。S3模型相对更老、更简单、结构更少。S4模型更新且单探讨S3模型的局限性和S4模型如何试图解决这些问题。
泛型函数
R使用对象的类来确定当一个泛型函数被调用时采取的行动。考虑下面的代码:
summary(women)
height weight
Min. :58.0 Min. :115.0
1st Qu.:61.5 1st Qu.:124.5
Median :65.0 Median :135.0
Mean :65.0 Mean :136.7
3rd Qu.:68.5 3rd Qu.:148.0
Max. :72.0 Max. :164.0
fit <- lm(weight ~ height, data=women)
summary(fit)
Call:
lm(formula = weight ~ height, data = women)
Residuals:
Min 1Q Median 3Q Max
-1.7333 -1.1333 -0.3833 0.7417 3.1167
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -87.51667 5.93694 -14.74 1.71e-09 ***
height 3.45000 0.09114 37.85 1.09e-14 ***
---
Signif. codes:
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 1.525 on 13 degrees of freedom
Multiple R-squared: 0.991, Adjusted R-squared: 0.9903
F-statistic: 1433 on 1 and 13 DF, p-value: 1.091e-14
第一个代码summary()函数对women数据框中的每个变量都进行了描述性分析。在第二个summary()函数对该数据框的线性回归进行了描述。这是如何发生的呢?
让我们来看看summary()函数的代码:
summary
function (object, ...) UseMethod("summary")
我们看看women数据框和fit对象的类:
class(women)
[1] "data.frame"
> class(fit)
[1] "lm"
如果函数summary.data.frame(women)存在,summary(women)函数执行summary.data.frame(women),否则执行summary.default(women).
同样,如果summary.lm(fit)存在,summary(fit)函数执行summary.lm(fit),否则执行summary.defalut(fir).
UseMethod()函数将对象分派给一个泛型函数,前提是该泛型函数有扩展与对象的类匹配。
为了列出可获得的S3泛型函数,可以使用methods()函数:
> methods(summary)
[1] summary.aov
[2] summary.aovlist*
[3] summary.aspell*
[4] summary.check_packages_in_dir*
[5] summary.connection
[6] summary.data.frame
[7] summary.Date
[8] summary.default
[9] summary.ecdf*
[10] summary.factor
[11] summary.glm
[12] summary.infl*
[13] summary.lm
[14] summary.loess*
[15] summary.manova
[16] summary.matrix
[17] summary.mlm*
[18] summary.nls*
[19] summary.packageStatus*
[20] summary.POSIXct
[21] summary.POSIXlt
[22] summary.ppr*
[23] summary.prcomp*
[24] summary.princomp*
[25] summary.proc_time
[26] summary.srcfile
[27] summary.srcref
[28] summary.stepfun
[29] summary.stl*
[30] summary.table
[31] summary.tukeysmooth*
[32] summary.warnings
返回的函数个数取决于机器安装的包的个数。在我的电脑上独立的summary()函数已经定义了32类。可以使用getAnywhere()函数查看代码,如getAnywhere(summary.glm)。
下面的代码清单定义了名为mymethod()的泛型函数。
#1.定义泛型函数
mymethod <- function(x, ...) UseMethod("mymethod")
mymethod.a <- function(x) print("Using A")
mymethod.b <- function(x) print("Using B")
mymethod.default <- function(x) print("Using Default")
#2.给对象分配类
x <- 1:5
y <- 6:10
z <- 10:15
class(x) <- "a"
class(y) <- "b"
#3.把泛型函数应用到对象中
mymethod(x)
[1] "Using A"
mymethod(y)
[1] "Using B"
mymethod(z)
[1] "Using Default"
#4.把泛型函数应用到包含两个类的对象中
class(z) <- c("a", "b")
mymethod(z)
[1] "Using A"
class(z) <- c("b", "a")
mymethod(z)
[1] "Using B"
#5.泛型函数没有默认为"c"的类
class(z) <- c("c","a", "b")
mymethod(z)
[1] "Using A"
一个对象可以被分配到一个以上的类,在这种情况下R如何决定使用哪个泛型函数呢?如4中对象z被分配到两类时,第一类用来决定哪个泛型函数被调用。在5中没有mymethod.c()函数,因此一下个类a被使用。
R从左到右搜索类的列表,寻找一个可用的泛型函数。