1

编辑:问题已经略微改变为为什么特定扩展不起作用,而不是为什么通用方法不起作用。

如标题所示,我无法将功能扩展到其他(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作为我的主要参考点,但其他来源总是很受欢迎。

干杯

4

2 回答 2

4

1. S3 中的泛型可以扩展,但是如果你想将非泛型变成泛型并扩展它,那么你将需要 S4。在这里,我们定义了一个 S4 泛型,默认为stats::cor. 然后我们让 S3 方法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,另一种方法是cor使用您自己的 S3 泛型:

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该页面上的参考资料和链接。

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

于 2013-07-12T13:44:26.510 回答
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不是通用的,所以你不能只定义一个方法。您还需要定义一个泛型,这就是您在问题的解决方案中所做的。

于 2013-07-12T11:34:43.570 回答