Handling missing arguments, handled with missing(), to call a function inside a function

Viewed 358

I am using rpart() inside a function myFunction(). rpart() accepts several parameters which are handled using the missing() function:

rpart(formula, data, weights, subset, na.action = na.rpart, method, model = FALSE, x = FALSE, y = TRUE, parms, control, cost, ...)

For example, the parameter method can be left unspecified, and is handled inside rpart() using the following code:

if (missing(method)) method <- "whatever default"

How can I pass the argument method as a parameter for myFunction() in the most simple and efficient way so that it handles the default missing argument?

If I do something like myFunction(foo = 0, method){# somecode; rpart(y ~ x, data = data, method = method)} then this throws an error,

argument "method" is missing, with no default

I have also tried with functions like rlang::missing() with no success whatsoever.

Of course an option is doing something like passing myFunction(method = NULL) and then using if-else statements to either pass or not pass this argument, but then I have to code each possibility (for 4 arguments that would be 16 calls) and is very clumsy.

Note that I would also like to avoid using the ellipsis, as I want to specifically name my arguments.


MINIMAL REPRODUCIBLE EXAMPLE:

y <- c(0,0.1,0.1,-0.1, 100, 101, 99)
x <- c(1,2,3,4, 100,101,102)

myFunction <- function(x, y,
                       method,
                       weights,
                       subset,
                       parms){
      rpart(formula = y ~ .,
            data = data.frame(y, x),
            weights = weights,
            subset = subset,
            parms = parms)
}

myFunction(x,y)

Error in eval(extras, data, env) : argument "weights" is missing, with no default

1 Answers

Here's a solution using match.call. This kind of pattern is seen quite often inside base R functions.

Consider the following function which we might find inside a package, with optional arguments:

package_fun <- function(x, method1, method2, method3)
{
  if(missing(method1)) method1 <- "Unspecified"
  if(missing(method2)) method2 <- "Unspecified"
  if(missing(method3)) method3 <- "Unspecified"
  data.frame(x, method1, method2, method3)
}

Inside our own function, we can build a call to package_fun that swaps in our own optional parameters, swaps out any we don't want to pass, and adds any additional ones we choose. We are left with a single call to package_fun, and don't need to worry about combinatorial explosion:

myFunction <- function(foo = 0, method1, method2, method3)
{
  mc <- match.call()
  mc[[1]] <- quote(package_fun)
  mc <- mc[-which(names(mc) == "foo")]
  mc$x <- foo
  eval(mc, env = parent.frame())
}

So now we can do:

myFunction(foo = 1, method1 = "Specified", method3 = "Specified")
#>   x   method1     method2   method3
#> 1 1 Specified Unspecified Specified

From the point of view of your reproducible example, this would look like:

myFunction <- function(x, y,
                       method,
                       weights,
                       subset,
                       parms){
  mc <- match.call()
  mc[[1]] <- quote(rpart)
  mc$formula <- y ~ .
  mc$data <- data.frame(y, x)
  mc$x <- NULL
  mc$y <- NULL
  eval(mc, envir =parent.frame())
}

So we would have:

myFunction(x,y)
#> n= 7 
#> 
#> node), split, n, deviance, yval
#>       * denotes terminal node
#> 
#> 1) root 7 17136.31 42.87143 *
Related