S4 setMethod 的 R 可选参数

标签 r oop s4

我有兴趣为泛型函数设置新方法。例如,假设我有一个新类(class)(例如 coolClass)。我可以编写一个包装器来计算该类的 log10 并使用以下代码轻松设置该方法:

setMethod("Math", c(x="coolClass"),
          function(x)
          {
            op = .Generic[[1]]
            switch(op,
                   `log10` = log10_for_coolClass(x),
                   stop("Undefined operation")
            )
          }
)

但是,我不知道如何设置一个方法来传递多个参数。例如,通用的 log 方法。运行 getGeneric("log") 显示以下内容:

> getGeneric("log")
standardGeneric for "log" defined from package "base"
  belonging to group(s): Math 

function (x, ...) 
standardGeneric("log", .Primitive("log"))
<bytecode: 0x2f9a958>
<environment: 0x2f937f0>
Methods may be defined for arguments: x
Use  showMethods("log")  for currently available ones.

看到这里,我希望我可以编写以下内容以传递可选的 base 参数。

setMethod("Math", signature(x="coolClass",...),
          function(x, ...)
          {
            op = .Generic[[1]]
            switch(op,
                   `log` = log_for_coolClass(x, ...),
                   stop("Undefined operation")
            )
          }
)

但是我得到以下错误:

Error in matchSignature(signature, fdef, where) : 
  '...' used in an incorrect context

尝试在 signature 中没有 ... 我得到一个不同的错误:

Error in rematchDefinition(definition, fdef, mnames, fnames, signature) : 
   methods can add arguments to the generic ‘Math’ only if '...' is an argument to the generic

这对我来说似乎很奇怪,因为 getGeneric 日志显示方法中的 ...

有什么想法吗?有没有办法捕获其他参数?我正在尝试更熟悉 S4 方法,但我对如何传递可选参数感到困惑。如果这是不可能的,如果有人能解释 log 函数是如何工作的,我将不胜感激,例如,假设该函数是 Math 组的一部分但接受多个参数。

更新

奇怪的是,如下所述,我可以使用 setMethod 直接在 log 上使用以下代码:

setMethod("log", signature(x="big.matrix"),
          function(x, base=exp(1))
            {
            log_for_coolClass(x, base=base)
          }
          )

然而,这并不能平息我的好奇心。例如,如果我在 Math 组中创建许多新方法,代码中如此重复似乎很奇怪。理想情况下,它看起来像这样:

setMethod("Math", c(x="coolClass"),
          function(x, base=exp(1))
          {
            op = .Generic[[1]]
            switch(op,
                   `log10` = log10_for_coolClass(x),
                   `log` = log_for_coolClass(x, base=base),
                   stop("Undefined operation")
            )
          }
)

最佳答案

这是一个类

.A <- setClass("A", representation(x="numeric"))

对于像log这样的函数,我们有

> getGeneric("log")
standardGeneric for "log" defined from package "base"
  belonging to group(s): Math 

function (x, ...) 
standardGeneric("log", .Primitive("log"))
<bytecode: 0x2b41b28>
<environment: 0x2b39df8>
Methods may be defined for arguments: x
Use  showMethods("log")  for currently available ones.

签名包括...。所以我们写

setMethod("log", "A", function(x, ...) {
    log(x@x, ...)
})

成功了

> log(.A(x=c(1, 2, NA)))
[1] 0.0000000 0.6931472        NA
> log(.A(x=c(1, 2, NA)), base=2)
[1]  0  1 NA

接下来:log10

> getGeneric("log10")
standardGeneric for "log10" defined from package "base"
  belonging to group(s): Math 

function (x) 
standardGeneric("log10", .Primitive("log10"))
<bytecode: 0x2b4a700>
<environment: 0x2b43138>
Methods may be defined for arguments: x
Use  showMethods("log10")  for currently available ones.

泛型中没有... 参数,所以我们基本上陷入困境——编写我们自己的泛型并实现包含... 的方法,或者编写一个没有 ... 参数的 log10,A 方法。

关于 ... 的相同原则适用于组泛型——Math 组泛型没有点

> getGeneric("Math")
groupGenericFunction for "Math" defined from package "base"

function (x) 
standardGeneric("Math")
<bytecode: 0x2771d40>
<environment: 0x275ee20>
Methods may be defined for arguments: x
Use  showMethods("Math")  for currently available ones.

所以我们的方法(实现所有数学运算,而不仅仅是日志;请注意,我们通常不会显式引用 .Generic)在我们类的对象上可能是

setMethod("Math", "A", function(x) {
    callGeneric(x@x)
})

现在我们有了所有数学函数的方法,例如,

> sqrt(.A(x=1:4))
[1] 1.000000 1.414214 1.732051 2.000000

此外,我们的日志变体 accepting ... 仍然可用,因此我们既可以为所有数学泛型定义类的行为,又可以为特定泛型提供专门的实现。

在这些组泛型的实现中可能存在一个应该解决的错误。如果在新 session 中我们定义了我们的类和 Math 泛型,但没有使用 ... 参数定义 log 函数,我们仍然可以调用

> log(.A(x=1:4))
[1] 0.0000000 0.6931472 1.0986123 1.3862944
> log(.A(x=1:4), base=2)
[1] 0.0000000 0.6931472 1.0986123 1.3862944

第二个参数被忽略但确实会导致错误。

关于S4 setMethod 的 R 可选参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27067795/

相关文章:

regex - 查找字符串中某个字符的位置

c++ - 拥有父子类层次结构,如何在单个 "Parent"类型变量中保存各种实际子级?

python - 强制使用专门的子类

r - R中 `subset`方法的多重分派(dispatch)

r - 如何原型(prototype)(启动)从其他插槽派生的 S4 插槽?

r - 为 S4 引用类的实例定义默认字段值

R如何通过创建新列在一行中写入可变数量的具有相同属性的行

r - 如何将table()转换为R中的矩阵

r - 如何在 purrr map 中传递数据帧和不均匀向量作为参数

java - 如何实例化 Java Bean 以使用其他 Bean 作为输入来保存计算值