【问题标题】:Why the parameter FUN in tapply is invalid combined with colwise为什么tapply中的参数FUN结合colwise无效
【发布时间】:2014-04-05 07:38:27
【问题描述】:

我通常使用colwisetapply 的组合来计算数据框中的分组值。但是,我意外地发现tapply 中的参数FUN 不能与plyr 中的colwise 一起正常工作。示例如下:

数据:

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)

谁能解释原因?提前谢谢你。

【问题讨论】:

  • 使用tapply 没有错,但是因为无论如何您都在加载plyr,所以更多plyr-esque 替代方案将是:sum_fun &lt;- function(x) sum(x[x &gt; 2]); ddply(.data = df, .variables = .(b), colwise(sum_fun))。这也为您提供了一个明确的“b”列。

标签: r plyr tapply


【解决方案1】:

好吧,问题在于lapplytapply 都有一个可选的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)。请注意,前三个(未命名的)参数现在是数据帧 tapplydb$b,上面的 FUN 参数排在最后。然而,这个参数是命名的。由于这是lapply 上的do.call,而不是该参数成为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 包应该检查名为FUN... 参数(或任何可能干扰lapply 工作的东西),但作者似乎没有包含这个。您可以向plyr 包提交拉取请求,该包实现以下任何变通方法:

定义一个本地

.lapply <- function(`*X*`, `*FUN*`, ...) lapply(X = `*X*`, `*FUN*`, ...)

(进一步减少干扰)。

colwise(tapply) 函数中检查names(list(...)) 中的XFUN(如果作者打算在子调用之前阻止对承诺的评估,可能会引入问题)。

使用命名为XFUN 显式调用do.call("lapply", ...),以便获得预期的结果

formal argument "FUN" matched by multiple actual arguments

【讨论】:

  • 罗伯特,非常感谢您出色的分步分析。
猜你喜欢
  • 1970-01-01
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多