Reputation: 648
It comes down to this:
df = data.frame(a = 1:10)
#example function that takes optional arguments
mymean <- function(x, w = 1, s = 0) { s + mean(w * x) }
summarize_(df, m = "mean(a)")
#> m
#> 1 5.5
summarize_(df, m = "mymean(a)")
#> Error: could not find function "mymean"
According to `vignette("nse") summarize_ must be given the formula syntax when using non-standard summarizing functions.
Ultimately, I want to be able to wrap summarize_
in a function like so:
my_summary <- function(df, x, ...) {
summarize_(df,
m = "mean(a)",
wm = "mymean(a, ...)" #gives error
}
#Partial working function
my_summary <- function(df, x, ...) {
summarize_(df,
m = "mean(a)", #works
wm1 = interp(mymean(a), a = as.name(x) #works but doesn't allow ...
wm2 = interp(mymean(a, b),
.values=list(a = as.name(x),
b = quote(...)), #doesn't work
wm3 = interp(mymean(a, ...), a = as.name(x) #doesn't work
}
A working function would allow me to call:
my_summary(df, a)
#> 5.5
my_summary(df, a, w=5, s=2)
#> 29.5
Upvotes: 10
Views: 428
Reputation: 545588
Since the problem is passing ...
to the function, one solution is to construct the call via call
and do.call
(yes, both):
library(dplyr)
df = data.frame(a = 1:10)
mymean = function(x, w = 1, s = 0)
s + mean(w * x)
my_summary = function (df, x, ...) {
x = as.name(substitute(x))
mycall = do.call(call, c('mymean', quote(x), list(...)))
summarize_(df,
m = lazyeval::interp(~mean(x), x = x),
w = lazyeval::lazy_(mycall, environment()))
}
my_summary(df, a)
#> m w
#> 1 5.5 5.5
my_summary(df, a, w = 5, s = 2)
#> m w
#> 1 5.5 29.5
Incidentally, the above also fixes passing the column name — I couldn’t get your code to work, and I don’t think it would work that way.
Upvotes: 6
Reputation: 648
This very hacky, horrible function does the trick, but what if mymean
contains many optional arguments?
mymean <- function(x, w=1, s = 0) { s + mean(w * x) }
my_summarize <- function(df, x, ...) {
vlist = list(...)
vlist_names = names(vlist)
if ("w" %in% vlist_names & "s" %in% vlist_names) {
res = summarize_(df, m = interp(~mymean(a, w=b, s=c),
.values = list(a = as.name(x),
b = vlist$w,
c = vlist$s)))
}
else if ("w" %in% vlist_names) {
res = summarize_(df, m = interp(~mymean(a, w=b),
.values = list(a = as.name(x),
b = vlist$w)))
}
else if ("s" %in% vlist_names) {
res = summarize_(df, m = interp(~mymean(a, s=c),
.values = list(a = as.name(x),
c = vlist$s)))
}
else {
res = summarize_(df, m = interp(~mymean(a), a = as.name(x)))
}
res
}
df = data.frame(a = 1:10)
my_summarize(df, "a")
#> m
#> 1 5.5
my_summarize(df, "a", s=5)
#> m
#> 1 10.5
my_summarize(df, "a", w=2)
#> m
#> 1 11
my_summarize(df, "a", w=2, s=5)
#> m
#> 1 16
Upvotes: 0