R:将功能扩展到其他(S3)类

时间:2013-07-12 11:30:37

标签: r oop

编辑:问题略有改变,为什么特定的扩展程序不起作用,而不是为什么一般方法不起作用。

如标题所示,我在将函数扩展到其他(S3)类时遇到了麻烦。

例如:

x <- y <- runif(10)
loessModel = loess(y ~ x)

methods("cor")
## [1] cor.test cor.test.default* cor.test.formula*

cor.loess = function(loessModel, ...) { cor(loessModel$x, loessModel$y, ...) }
cor(loessModel)
## Error in cor(loessModel) : supply both 'x' and 'y' or a matrix-like 'x'

但是,以下工作:

getCor = function(x, y, ...) { UseMethod("getCor") }
getCor.default = function(x, y, ...) { cor(x, y, ...) }
getCor.loess = function(loessModel, ...) getCor(loessModel$x, loessModel$y, ...)
getCor(loessModel)
## [,1]
## x    1

所以...正如Josh所解释的,扩展cor的第一种方法不起作用,因为cor不是通用函数。第二种方法有效,但我无法将其扩展为LoessList类。这对我来说很困惑,特别是因为它在“功能之外”起作用:

set.seed(13)
df = data.frame(id = rep.int(1:2, 10), 
                x = runif(20), 
                y = runif(20))

loessList = structure(dlply(df, "id", loess, formula = as.formula("y ~ x")),
                      class = "LoessList")

getCor.LoessList = function(loessList, ...) { ldply(loessList, getCor, ...) }
getCor(loessList)
## Error in is.data.frame(y) : argument "y" is missing, with no default

ldply(loessList, getCor)
##   id           1
## 1  1 -0.01552707
## 2  2 -0.38997723

更一般地说,R中的OOP有什么好的指南吗?我一直使用http://logic.sysbiol.cam.ac.uk/teaching/advancedR/slides.pdf作为我的主要参考点,但其他来源总是受到赞赏。

干杯

2 个答案:

答案 0 :(得分:4)

1。 S3中的泛型可以扩展但是如果你想将非泛型变成泛型并扩展它,那么你将需要S4。这里我们定义一个S4泛型,默认为stats::cor。然后我们将S4方法loess提供给S4并定义loess方法:

setGeneric("cor", function(x, ...) stats::cor(x, ...))
setOldClass("loess") # let S4 use an S3 class
setMethod("cor", list(x = "loess"), 
   def = function(x, ...) callNextMethod(x$x, x$y, ...))

现在我们可以这样做:

example(loess)
cor(cars.lo)

2。如果您想坚持使用S3,另一种方法是使用您自己的S3通用来破解cor

cor <- function(x, ...) UseMethod("cor")
cor.default <- stats::cor
cor.loess <- function(x, ...) stats::cor(x$x, x$y, ...)

example(loess)
cor(cars.lo)

3。当然,您可以恰当地重新定义cor并忘记OO派遣。实际上存在一些潜在的问题,因为它使cor对执行实际工作的函数的父框架调用,但在许多情况下它并不重要。 (请参阅lm源代码以了解如何规避此问题。)

cor <- function(x, ...) {
    if (inherits(x, "loess")) return(cor(x$x, x$y, ...))
    stats::cor(x, ...)
}

信息:有关S3的信息,请参阅该页面上的?UseMethod以及参考和链接。有关S4的信息,请参阅?Methods以及该页面上的参考和链接。

更新:添加了其他方法和参考。

答案 1 :(得分:3)

运行methods(cor)时注意警告。

R> methods("cor")
[1] cor.test          cor.test.default* cor.test.formula*

   Non-visible functions are asterisked
Warning message:
In methods("cor") : function 'cor' appears not to be generic

cor不是通用的,因此您不能只定义方法。您也需要定义泛型,这就是您在问题的解决方案中所做的。