我刚刚开始处理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)
这两个都应该对你有用。