我通常使用colwise
和tapply
的组合来计算数据框中的分组值。但是,我意外地发现FUN
中的参数tapply
无法与colwise
中的plyr
一起正常工作。示例如下:
数据:
df <- data.frame(a = 1:10, b = rep(1:2, each = 5), c = 2:11)
正常:
library(plyr)
colwise(tapply)(subset(df, select = c(a, c)), df$b, function(x){sum(x[x > 2])})
以上代码是正确的,可以正常工作。但如果我添加FUN
,那就错了:
colwise(tapply)(subset(df, select = c(a, c)), df$b, FUN = function(x){sum(x[x > 2])})
错误是:
Error in FUN(X[[1L]], ...) :
unused arguments (function (X, INDEX, FUN = NULL, ..., simplify = TRUE)
{
FUN <- if (!is.null(FUN)) match.fun(FUN)
if (!is.list(INDEX)) INDEX <- list(INDEX)
nI <- length(INDEX)
if (!nI) stop("'INDEX' is of length zero")
namelist <- vector("list", nI)
names(namelist) <- names(INDEX)
extent <- integer(nI)
nx <- length(X)
one <- 1
group <- rep.int(one, nx)
ngroup <- one
for (i in seq_along(INDEX)) {
index <- as.factor(INDEX[[i]])
if (length(index) != nx) stop("arguments must have same length")
namelist[[i]] <- levels(index)
extent[i] <- nlevels(index)
group <- group + ngroup * (as.integer(index) - one)
ngroup <- ngroup * nlevels(index)
}
if (is.null(FUN)) return(group)
ans <- lapply(X = split(X, group), FUN = FUN, ...)
index <- as.integer(names(ans))
if (simplify && all(unlist(lapply(ans, length)) == 1)) {
ansmat <- array(dim = extent, dimnames = namelist)
有人可以解释原因吗?提前谢谢。
答案 0 :(得分:0)
嗯,问题是lapply
和tapply
都有一个可选的FUN
参数。请注意,colwise(tapply)
是一个包含以下行的函数:
out <- do.call("lapply", c(list(filtered, .fun, ...), dots))
让我们通过编写
来使用我们的调试器ct <- colwise(tapply); trace(ct, quote(browser()), at = 6)
然后运行
ct(subset(df, select = c(a, c)), df$b, FUN = function(x){sum(x[x > 2])})
现在让我们打印c(list(filtered, .fun, ...), dots)
。请注意,前三个(未命名)参数现在是数据框tapply
和db$b
,上面的FUN
参数最后出现。但是,此参数是命名为。由于这是do.call
上的lapply
,而不是该参数成为tapply
的可选参数,它现在成为lapply
的主要调用!所以发生的事情就是你要把它变成:
lapply(subset(df, select = c(a, c)), function(x){sum(x[x > 2])}, tapply, df$b)
当然,这没有任何意义,如果您手动执行上述(仍在调试器中),您将得到完全相同的错误。有关简单的解决方法,请尝试:
tapply2 <- function(.FUN, ...) tapply(FUN = .FUN, ...)
colwise(tapply2)(subset(df, select = c(a, c)), df$b, .FUN = function(x){sum(x[x > 2])})
plyr
包应检查名为...
的{{1}}个参数(或任何可能干扰FUN
工作的内容),但它似乎不是作者包括这个。您可以向执行以下任何变通办法的lapply
包提交拉取请求:
定义本地
plyr
(进一步减少干扰)。
检查.lapply <- function(`*X*`, `*FUN*`, ...) lapply(X = `*X*`, `*FUN*`, ...)
函数中的names(list(...))
colwise(tapply)
和X
(如果作者打算在子调用之前阻止对promises进行评估,则可能会出现问题)。
使用已命名的FUN
和do.call("lapply", ...)
明确调用X
,以便获得预期的
FUN