Nested dplyr-based function within another function

时间:2015-07-31 20:18:41

标签: r dplyr

Thanks to @MrFlick I can handle with the problem in usage dplyr function within my own function. But another problem came up. After implementing test_function:

test_function <- function(.data, ..., variable, FUN){
    dots <- eval(bquote(~FUN(.(substitute(variable)))))
    group_by_(.data,.dots = lazyeval::lazy_dots(...)) %>% 
    summarise_(.dots = dots)
}

I wanted to use this function within another function to do sth more:

test_function2 <– function(data, ..., variable, FUN) { 
   test_function(data, ..., variable, FUN) 
   # another computation
} 

and after that I tried:

test_function2(diamonds, cut, clarity, variable = price, FUN - mean)

in a result I got an error : Error: Could not find object price. Why?

2 个答案:

答案 0 :(得分:3)

This is why trying to use non-standard evaluation can be a big mess. The first problem you have is the issue of named parameters and ... parameters. If you want to use parameters after dots, they must be named in the call, for example

test_function(data, ..., variable=variable, FUN=FUN) 

otherwise they would just wind up with everything else in the ....

The next problem is that now the parameter you are passing to variable= is variable. THis means, when test_function tries substitute(), it just get's back variable. R can't tell when you want to resolve the symbol name. It basically looks the same as

test_function(data, ..., variable=price, FUN=mean) 

One way to deal with this complicated next call is to use match.call(). Here we do a bit of extra work because you renamed the data parameter

test_function2 <- function(data, ..., variable, FUN) { 
   mc <- match.call()
   mc[[1]] <- quote(test_function)
   mc$.data <- mc$data
   mc$data <- NULL
   eval(mc)
}

basically we just take everything that was passed to test_function2 and pass it along to test_function.

答案 1 :(得分:1)

You can also just tell substitute where it should look for variable, adding this line to test_function (plus using variable=variable and FUN=FUN when passing those arguments)

test_function <- function(.data, ..., variable, FUN){
    e <- parent.frame()
    dots <- eval(bquote(~FUN(.(substitute(variable, env=e)))))
    ...