将相同S4方法的R个不同自变量应用于不同的类



我刚刚开始处理S4对象,我想用S3实现一些看起来很简单的东西,但我不知道如何用S4类实现。

使用S3,通过使用UseMethod()可以很容易地创建一个构造函数,该构造函数根据输入的类别表现不同,例如:

.Foo <- function(...) UseMethod(".Foo")
.Foo.character <- function(x, y, z) {
y <- as.factor(y)
structure(data.frame(y, z, x, stringsAsFactors = FALSE),
class = c('Foo', 'data.frame'))
}
.Foo.numeric <- function(x, ...) {
.Foo(x = as.character(x), ...)
}
.Foo.data.frame <- function(df) {
do.call(what = .Foo, args = df[, c('x', 'y', 'z')]) 
}

通过这种方式,给定一个数据帧,我们可以将.Foo()应用到它上,并得到Foo:类的对象

df <- data.frame(x = 1:4, y = c(2,2,3,3), z = 5:8)
tmp <- .Foo(df)
str(tmp)

打印:

Classes ‘Foo’ and 'data.frame': 4 obs. of  3 variables:
$ y: Factor w/ 2 levels "2","3": 1 1 2 2
$ z: int  2 3 4 5
$ x: chr  "1" "2" "3" "4"

现在,尝试使用S4做同样的事情我有:

  • 首先创建一个Foo类:
setOldClass("data.frame")
Foo <- setClass("Foo",
contains = "data.frame"
)
  • 然后我们创建一个通用.Foo
setGeneric(".Foo", function(x, ...) standardGeneric(".Foo"))
  • 最后我们为它创建了方法:
setMethod(".Foo", signature("character"), function(x, y, z) {
y <- as.factor(y)
Foo(data.frame(y, z, x, stringsAsFactors = FALSE))
})
setMethod(".Foo", signature("numeric"), function(x, ...) {
.Foo(x = as.character(x), ...)
})
setMethod(".Foo", signature("data.frame"), function(x) {
do.call(what = .Foo, args = x[, c("x", "y", "z")])
})

str(.Foo(df))之后我们得到:

'data.frame':   4 obs. of  3 variables:
Formal class 'Foo' [package ".GlobalEnv"] with 4 slots
..@ .Data    :List of 3
.. ..$ : Factor w/ 2 levels "2","3": 1 1 2 2
.. ..$ : int  2 3 4 5
.. ..$ : chr  "1" "2" "3" "4"
..@ names    : chr  "y" "z" "x"
..@ row.names: int  1 2 3 4
..@ .S3Class : chr "data.frame"

因此,这种方法行之有效。现在我的问题是:这样做正确吗?如果我想用.Food.data.framedf而不是x作为参数,我可以吗?或者我不能,因为所有第一个输入都必须与Generic中定义的名称相同?我能做点什么吗:

setGeneric(".Foo", function(x, df, ...) standardGeneric(".Foo"))
setMethod(".Foo", signature("character"), function(x, y, z) {
y <- as.factor(y)
Foo(data.frame(y, z, x, stringsAsFactors = FALSE))
})
setMethod(".Foo", signature("numeric"), function(x, ...) {
.Foo(x = as.character(x), ...)
})
setMethod(".Foo", signature(x = "missing", df = "data.frame"), function(df) {
do.call(what = .Foo, args = df[, c('x', 'y', 'z')])
})
.Foo(df)

但这失败了,错误

Error in (function (classes, fdef, mtable)  : 
unable to find an inherited method for function ‘.Foo’ for signature ‘"data.frame", "missing"’

提前感谢!如果我过度拉伸或解释错误,我很抱歉,但这是我第一次使用S4,我找不到信息,只有非常简单的信息。

错误的原因是参数匹配。

.Foo(df)

被解释为

.Foo(
x=df,
df=(missing),
...=(empty list)
)

这就是R在返回签名(data.frame, missing)时试图告诉你的——它为签名(foo, missing)寻找了一个方法,但没有找到,尝试了超类(即data frame(,也没有找到该签名的方法。

如果要将对象df指定为参数df,则可以显式将其命名为

.Foo(df=df)

或使用位置匹配:

.Foo(,df)

这两个都应该对你有用。

最新更新