如何为 data.frame 子类扩展 rbind?
How do you extend rbind for a data.frame subclass?
我的问题是如何扩展 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()
}
我意识到在这种情况下不需要扩展 rbind()
,但我的宏伟计划是在我的子类上使用 rbind.data.frame()
,然后向它的子类添加一些额外的 checks/attributes结果。
如果您调用以下内容,则会收到错误消息:Error in NextMethod() : generic function not specified
。
无效:
t1 <- data.frame(a = 1:12, b = month.abb)
t2 <- new_df2(t1)
rbind(t2, t2)
我也尝试使用 NextMethod(generic = "rbind")
,但在那种情况下,您会收到此错误:Error in NextMethod(generic = "rbind") : wrong value for .Method
.
也不行:
rbind.df2 <- function(..., deparse.level = 1)
{
NextMethod(generic = "rbind")
}
rbind(t2, t2)
我无计可施,猜测我对 subclasses/methods 的理解也有局限性。感谢您的帮助。
答案是扩展 rbind2
,而不是 rbind
。来自 rbind2
的帮助页面:
“这些是具有默认方法的 (S4) 通用函数。
...
cbind2(rbind2)的主要用途是在满足这两个要求的情况下,通过cbind()(rbind())递归调用:
至少有一个参数是S4对象,并且
S3 调度失败(参见 cbind 下的调度部分)。
我将在下面处理 rbind()
的具体情况,但我首先要注意的是,我们可以生成更多示例,表明当第一个参数为 [=17= 时,NextMethod()
通常没有问题](关于赏金请求):
f <- function(..., b = 3) UseMethod("f")
f.a <- function(..., b = 3) { print("yes"); NextMethod() }
f.integer <- function(..., b = 4) sapply(list(...), "*", b)
x <- 1:10
class(x) <- c("a", class(x))
f(x)
[1] "yes"
[,1]
[1,] 4
[2,] 8
[3,] 12
[4,] 16
[5,] 20
[6,] 24
[7,] 28
[8,] 32
[9,] 36
[10,] 40
f(x, b = 5)
[1] "yes"
[,1]
[1,] 5
[2,] 10
[3,] 15
[4,] 20
[5,] 25
[6,] 30
[7,] 35
[8,] 40
[9,] 45
[10,] 50
那么为什么 rbind.df2 不起作用?
事实证明,rbind()
和 cbind()
不是 普通 泛型。首先,它们是内部通用的;请参阅 "Internal Generics" 部分 here from Hadley Wickham's old S3 page on Advanced R, or this excerpt from the current Advanced R:
Some S3 generics, like [, sum(), and cbind(), don’t call UseMethod()
because they are implemented in C. Instead, they call the C functions
DispatchGroup() or DispatchOrEval().
这还不足以给我们带来麻烦,正如我们以 sum()
为例所见:
sum.a <- function(x, na.rm = FALSE) { print("yes"); NextMethod() }
sum(x)
[1] "yes"
[1] 55
但是,对于 rbind
和 cbind
,它甚至更奇怪,正如 source code(从第 1025 行开始)的评论中所认识到的那样:
/* cbind(deparse.level, ...) and rbind(deparse.level, ...) : */
/* This is a special .Internal */
...(省略部分代码)...
/* Lazy evaluation and method dispatch based on argument types are
* fundamentally incompatible notions. The results here are
* ghastly.
在那之后,给出了一些调度规则的解释,但到目前为止我还没有能够使用这些信息来使 NextMethod()
工作。在上面给出的用例中,我会按照评论中 F. Privé 的建议执行以下操作:
new_df2 <- function(x, ...)
{
stopifnot(is.data.frame(x))
structure(x, class = c("df2", "data.frame"))
}
rbind.df2 <- function(..., deparse.level = 1)
{
print("yes") # Or whatever else you want/need to do
base::rbind.data.frame(..., deparse.level = deparse.level)
}
t1 <- data.frame(a = 1:12, b = month.abb)
t2 <- new_df2(t1)
rbind(t2, t2)
[1] "yes"
a b
1 1 Jan
2 2 Feb
3 3 Mar
4 4 Apr
5 5 May
6 6 Jun
7 7 Jul
8 8 Aug
9 9 Sep
10 10 Oct
11 11 Nov
12 12 Dec
13 1 Jan
14 2 Feb
15 3 Mar
16 4 Apr
17 5 May
18 6 Jun
19 7 Jul
20 8 Aug
21 9 Sep
22 10 Oct
23 11 Nov
24 12 Dec
我的问题是如何扩展 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()
}
我意识到在这种情况下不需要扩展 rbind()
,但我的宏伟计划是在我的子类上使用 rbind.data.frame()
,然后向它的子类添加一些额外的 checks/attributes结果。
如果您调用以下内容,则会收到错误消息:Error in NextMethod() : generic function not specified
。
无效:
t1 <- data.frame(a = 1:12, b = month.abb)
t2 <- new_df2(t1)
rbind(t2, t2)
我也尝试使用 NextMethod(generic = "rbind")
,但在那种情况下,您会收到此错误:Error in NextMethod(generic = "rbind") : wrong value for .Method
.
也不行:
rbind.df2 <- function(..., deparse.level = 1)
{
NextMethod(generic = "rbind")
}
rbind(t2, t2)
我无计可施,猜测我对 subclasses/methods 的理解也有局限性。感谢您的帮助。
答案是扩展 rbind2
,而不是 rbind
。来自 rbind2
的帮助页面:
“这些是具有默认方法的 (S4) 通用函数。
...
cbind2(rbind2)的主要用途是在满足这两个要求的情况下,通过cbind()(rbind())递归调用:
至少有一个参数是S4对象,并且
S3 调度失败(参见 cbind 下的调度部分)。
我将在下面处理 rbind()
的具体情况,但我首先要注意的是,我们可以生成更多示例,表明当第一个参数为 [=17= 时,NextMethod()
通常没有问题](关于赏金请求):
f <- function(..., b = 3) UseMethod("f")
f.a <- function(..., b = 3) { print("yes"); NextMethod() }
f.integer <- function(..., b = 4) sapply(list(...), "*", b)
x <- 1:10
class(x) <- c("a", class(x))
f(x)
[1] "yes"
[,1]
[1,] 4
[2,] 8
[3,] 12
[4,] 16
[5,] 20
[6,] 24
[7,] 28
[8,] 32
[9,] 36
[10,] 40
f(x, b = 5)
[1] "yes"
[,1]
[1,] 5
[2,] 10
[3,] 15
[4,] 20
[5,] 25
[6,] 30
[7,] 35
[8,] 40
[9,] 45
[10,] 50
那么为什么 rbind.df2 不起作用?
事实证明,rbind()
和 cbind()
不是 普通 泛型。首先,它们是内部通用的;请参阅 "Internal Generics" 部分 here from Hadley Wickham's old S3 page on Advanced R, or this excerpt from the current Advanced R:
Some S3 generics, like [, sum(), and cbind(), don’t call UseMethod() because they are implemented in C. Instead, they call the C functions DispatchGroup() or DispatchOrEval().
这还不足以给我们带来麻烦,正如我们以 sum()
为例所见:
sum.a <- function(x, na.rm = FALSE) { print("yes"); NextMethod() }
sum(x)
[1] "yes"
[1] 55
但是,对于 rbind
和 cbind
,它甚至更奇怪,正如 source code(从第 1025 行开始)的评论中所认识到的那样:
/* cbind(deparse.level, ...) and rbind(deparse.level, ...) : */
/* This is a special .Internal */
...(省略部分代码)...
/* Lazy evaluation and method dispatch based on argument types are
* fundamentally incompatible notions. The results here are
* ghastly.
在那之后,给出了一些调度规则的解释,但到目前为止我还没有能够使用这些信息来使 NextMethod()
工作。在上面给出的用例中,我会按照评论中 F. Privé 的建议执行以下操作:
new_df2 <- function(x, ...)
{
stopifnot(is.data.frame(x))
structure(x, class = c("df2", "data.frame"))
}
rbind.df2 <- function(..., deparse.level = 1)
{
print("yes") # Or whatever else you want/need to do
base::rbind.data.frame(..., deparse.level = deparse.level)
}
t1 <- data.frame(a = 1:12, b = month.abb)
t2 <- new_df2(t1)
rbind(t2, t2)
[1] "yes"
a b
1 1 Jan
2 2 Feb
3 3 Mar
4 4 Apr
5 5 May
6 6 Jun
7 7 Jul
8 8 Aug
9 9 Sep
10 10 Oct
11 11 Nov
12 12 Dec
13 1 Jan
14 2 Feb
15 3 Mar
16 4 Apr
17 5 May
18 6 Jun
19 7 Jul
20 8 Aug
21 9 Sep
22 10 Oct
23 11 Nov
24 12 Dec