如何为 data.frame 子类扩展 rbind ?

r_a*_*anb 5 generics methods r rbind r-s3

我的问题是如何扩展rbind()子类data.frame?我似乎无法正确扩展rbind()以使用即使是非常简单的子类。以下示例演示了该问题:

子类和方法定义:

new_df2 <- function(x, ...)
{
  stopifnot(is.data.frame(x))
  structure(x, class = c("df2", "data.frame"), author = "some user")
}

rbind.df2 <- function(..., deparse.level = 1)
{
  NextMethod()
}
Run Code Online (Sandbox Code Playgroud)

我意识到rbind()在这种情况下扩展是不必要的,但我的宏伟计划是在我的子类上使用rbind.data.frame(),然后向其结果添加一些额外的检查/属性。

如果您调用以下命令,您会收到错误:Error in NextMethod() : generic function not specified

不起作用:

t1 <- data.frame(a = 1:12, b = month.abb)
t2 <- new_df2(t1)
rbind(t2, t2)
Run Code Online (Sandbox Code Playgroud)

我也尝试过使用NextMethod(generic = "rbind"),但在这种情况下,您会收到此错误:Error in NextMethod(generic = "rbind") : wrong value for .Method

也不起作用:

rbind.df2 <- function(..., deparse.level = 1)
{
  NextMethod(generic = "rbind")
}

rbind(t2, t2)
Run Code Online (Sandbox Code Playgroud)

我也束手无策,猜测我对子类/方法的理解的局限性。谢谢你的帮助。

duc*_*ayr 3

我将处理下面的具体情况,但我首先要注意的是,我们可以生成其他示例,表明当第一个参数为(关于赏金请求)时rbind(),通常不会出现问题:NextMethod()...

\n\n
f <- function(..., b = 3) UseMethod("f")\nf.a <- function(..., b = 3) { print("yes"); NextMethod() }\nf.integer <- function(..., b = 4) sapply(list(...), "*", b)\nx <- 1:10\nclass(x) <- c("a", class(x))\nf(x)\n\n[1] "yes"\n      [,1]\n [1,]    4\n [2,]    8\n [3,]   12\n [4,]   16\n [5,]   20\n [6,]   24\n [7,]   28\n [8,]   32\n [9,]   36\n[10,]   40\n\nf(x, b = 5)\n\n[1] "yes"\n      [,1]\n [1,]    5\n [2,]   10\n [3,]   15\n [4,]   20\n [5,]   25\n [6,]   30\n [7,]   35\n [8,]   40\n [9,]   45\n[10,]   50\n
Run Code Online (Sandbox Code Playgroud)\n\n

那么为什么 rbind.df2 不起作用呢?

\n\n

事实证明,rbind()cbind()不是普通的仿制药。首先,它们在内部是通用的;请参阅 Hadley Wickham 在 Advanced R 上的旧 S3 页面中的“内部泛型”部分,或者当前Advanced R的摘录:

\n\n
\n

一些 S3 泛型,如 [、sum() 和 cbind(),不\xe2\x80\x99t 调用 UseMethod()\n 因为它们是在 C 中实现的。相反,它们调用 C 函数\n DispatchGroup() 或 DispatchOrEval ()。

\n
\n\n

这还不足以给我们带来麻烦,正如我们可以看到的sum()那样:

\n\n
sum.a <- function(x, na.rm = FALSE) { print("yes"); NextMethod() } \nsum(x)\n\n[1] "yes"\n[1] 55\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而, forrbindcbind更奇怪,正如源代码中的注释所识别的那样(从第 1025 行左右开始):

\n\n
/* cbind(deparse.level, ...) and rbind(deparse.level, ...) : */\n/* This is a special .Internal */\n
Run Code Online (Sandbox Code Playgroud)\n\n

...(省略部分代码)...

\n\n
    /* Lazy evaluation and method dispatch based on argument types are\n     * fundamentally incompatible notions.  The results here are\n     * ghastly.\n
Run Code Online (Sandbox Code Playgroud)\n\n

之后,给出了调度规则的一些解释,但到目前为止我还无法使用该信息来进行NextMethod()工作。在上面给出的用例中,我将遵循评论中F.Priv\xc3\xa9的建议并执行以下操作:

\n\n
new_df2 <- function(x, ...)\n{\n    stopifnot(is.data.frame(x))\n    structure(x, class = c("df2", "data.frame"))\n}\n\nrbind.df2 <- function(..., deparse.level = 1)\n{\n    print("yes") # Or whatever else you want/need to do\n    base::rbind.data.frame(..., deparse.level = deparse.level)\n}\n\nt1 <- data.frame(a = 1:12, b = month.abb)\nt2 <- new_df2(t1)\nrbind(t2, t2)\n\n[1] "yes"\n    a   b\n1   1 Jan\n2   2 Feb\n3   3 Mar\n4   4 Apr\n5   5 May\n6   6 Jun\n7   7 Jul\n8   8 Aug\n9   9 Sep\n10 10 Oct\n11 11 Nov\n12 12 Dec\n13  1 Jan\n14  2 Feb\n15  3 Mar\n16  4 Apr\n17  5 May\n18  6 Jun\n19  7 Jul\n20  8 Aug\n21  9 Sep\n22 10 Oct\n23 11 Nov\n24 12 Dec\n
Run Code Online (Sandbox Code Playgroud)\n