Well, the issue is that both lapply
and tapply
have an optional FUN
argument. Note that colwise(tapply)
is a function with the following line:
out <- do.call("lapply", c(list(filtered, .fun, ...), dots))
Let's go to this line with our debugger by writing
ct <- colwise(tapply); trace(ct, quote(browser()), at = 6)
and then running
ct(subset(df, select = c(a, c)), df$b, FUN = function(x){sum(x[x > 2])})
Now let's print c(list(filtered, .fun, ...), dots)
. Notice that the first three (unnamed) arguments are now the dataframe, tapply
, and db$b
, with the FUN
argument above coming in last. However, this argument is named. Since this is a do.call
on lapply
, instead of that argument becoming an optional parameter for tapply
, it now becomes the main call on lapply
! So what is happening is that you are turning this into:
lapply(subset(df, select = c(a, c)), function(x){sum(x[x > 2])}, tapply, df$b)
This, of course, makes no sense, and if you execute the above (still in your debugger) manually, you will get the exact same error you are getting. For a simple workaround, try:
tapply2 <- function(.FUN, ...) tapply(FUN = .FUN, ...)
colwise(tapply2)(subset(df, select = c(a, c)), df$b, .FUN = function(x){sum(x[x > 2])})
The plyr
package should be checking for ...
arguments named FUN
(or anything that can interfere with lapply
's job), but it doesn't seem the author included this. You can submit a pull request to the plyr
package that implements any of the following workarounds:
Defines a local
.lapply <- function(`*X*`, `*FUN*`, ...) lapply(X = `*X*`, `*FUN*`, ...)
(minimizing interference further).
Checks names(list(...))
within the colwise(tapply)
function for X
and FUN
(can introduce problems if the author intended to prevent evaluation of promises until the child call).
Calls do.call("lapply", ...)
explicitly with named X
and FUN
, so that you get the intended
formal argument "FUN" matched by multiple actual arguments