背景R
函数rbind()
和cbind()
的调度机制是非标准的。我探讨了当参数之一是rbind.myclass()
时编写cbind.myclass()
或data.frame
函数的一些可能性,但是到目前为止,我还没有令人满意的方法。这篇文章集中在rbind
上,但对于cbind
也是如此。
问题
让我们创建一个rbind.myclass()
函数,该函数在被调用时简单地回显。
rbind.myclass <- function(...) "hello from rbind.myclass"
我们创建一个类
myclass
的对象,以下所有对rbind
的调用正确调度到
rbind.myclass()
a <- "abc"
class(a) <- "myclass"
rbind(a, a)
rbind(a, "d")
rbind(a, 1)
rbind(a, list())
rbind(a, matrix())
但是,当其中一个参数(不必是第一个参数)时,
rbind()
将改为调用base::rbind.data.frame()
:rbind(a, data.frame())
这种行为有点令人惊讶,但实际上已记录在
dispatch
的rbind()
部分。那里给出的建议是:如果要将其他对象与数据框组合在一起,
可能有必要先将其强制为数据帧。
实际上,此建议可能难以实施。转换为数据框可能会删除基本类信息。此外,发出命令
rbind(a, x)
后,可能不了解建议的用户可能会遇到错误或意外结果。方法
警告用户
第一种可能性是警告用户,当
rbind(a, x)
是数据帧时,不应调用x
。相反,包mypackage
的用户应显式调用隐藏函数:mypackage:::rbind.myclass(a, x)
可以这样做,但是用户必须记住在需要时进行显式调用。调用隐藏函数是万不得已的方法,不应作为常规策略。
拦截
rbind
另外,我试图通过拦截调度来屏蔽用户。我的第一次尝试是提供
base::rbind.data.frame()
的本地定义:rbind.data.frame <- function(...) "hello from my rbind.data.frame"
rbind(a, data.frame())
rm(rbind.data.frame)
这失败了,因为没有欺骗
rbind()
从rbind.data.frame
调用.GlobalEnv
,并照常调用base
版本。另一种策略是用局部函数覆盖
rbind()
,这在S3 dispatching of `rbind` and `cbind`中建议。rbind <- function (...) {
if (attr(list(...)[[1]], "class") == "myclass") return(rbind.myclass(...))
else return(base::rbind(...))
}
这非常适合调度到
rbind.myclass()
,因此用户现在可以为任何类型的对象rbind(a, x)
键入x
。rbind(a, data.frame())
缺点是在
library(mypackage)
之后,我们收到消息The following objects are masked from ‘package:base’: rbind
。尽管从技术上讲一切都按预期工作,但应该有比
base
函数替代更好的方法。结论
上述选择都不令人满意。我已经阅读了有关使用S4调度的替代方法的信息,但到目前为止,我还没有找到该想法的任何实现。任何帮助或指示吗?
最佳答案
正如您自己提到的那样,使用S4将是一个很好的解决方案。我最近没有对数据帧进行过调查,因为我对我的长期CRAN软件包“ Matrix”(=“ recommended”,即每个R分布的一部分)和“ Rmpfr”都对其他广义矩阵更感兴趣。
实际上,甚至有两种不同的方式:
1)Rmpfr
使用新方法为rbind()/ cbind()中的'...'定义方法。
这在?dotsMethods
(助记符:'...'=点)中有很好的记录,并在Rmpfr / R / array中实现。R第511 ff行(例如https://r-forge.r-project.org/scm/viewvc.php/pkg/R/array.R?view=annotate&root=rmpfr)
2)Matrix
通过为rbind2()和cbind2()定义(S4)方法来使用较旧的方法:如果您阅读?rbind
的确提及了使用rbind2 / cbind2的情况。那里的想法:“ 2”表示您为两个(“ 2”)类似矩阵的对象定义签名的S4方法,并且rbind / cbind递归地将它们用于其两个潜在的多个参数。
关于r - rbind和cbind为data.frame的分派(dispatch),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47967264/