如何将'...'中包含的参数传递给R

时间:2018-11-22 05:00:33

标签: r function arguments

我在通过递归调用integrate函数传递参数时遇到麻烦。这是一个简单的例子,说明了我的难题。

考虑一个函数foo1,该函数需要参数x并返回x的某些转换。例如:

foo1 = function(x, alpha = 1.5) {
  return(x^alpha)
}

现在考虑一个函数foo2,它也需要x并返回一些不同的转换:

foo2 = function(x, y, z) {
  return(x * y * z)
}

现在考虑一个函数bar,该函数返回任何类似x的函数的有限积分(从xMaxfoo),但是接受一个多个值的向量x

bar = function(xVals, xMax, ..., fun) {
  return(
    sapply(
      xVals,
      function(xVal) integrate(f = fun, lower = xVal, upper = xMax, ...)$value)
  )
}

请注意,foo1的参数alpha将作为...的一部分传递:

bar(10:20, 100, alpha = 1.5, fun = foo1)  

foo2的参数yz也将作为...的一部分传递:

bar(10:20, 100, y = 2, z = 4, fun = foo2)

我喜欢这种安排,因为integrate的其他必需参数也可以作为...的一部分传递。例如,要更改subdivisions调用的integrate函数的bar参数的默认值,只需指定:

bar(10:20, 100, y = 2, z = 4, fun = foo2, subdivisions = 200L)

现在,考虑一个将bar从xStart集成到xEnd,但接受xStart和xEnd的多个值的向量的函数。可能看起来像这样:

integrateBar = function(xStart, xEnd, xMax, ..., fun) {
  aMatrix = cbind(xStart, xEnd)
  result =
    apply(
      aMatrix,
      1,
      function(xRange) integrate(bar, xRange[1], xRange[2], xMax, ..., fun = fun)$value
    )
  return(result)
}

所以这很好并且很简单,直到我想调用integrateBar,但要为subdivisions中调用的integrate函数更改bar参数的值。如果我使用:

integrateBar(10:20, 40, 100, alpha = 1.5, subdivisions = 200L, fun = foo1)

subdivisions参数由integrate中的integrateBar函数捕获和使用,并且不传递给bar。这是理想的行为-有时。但是有时我也希望能够将subdivisionsintegrate调用的integrateBar保留为默认设置,而将integratebar的调用更改为默认设置。有人可以告诉我一种优雅的方法吗?

我愿意为bar修改形式,但我也不想让它过于笨拙,因为我也想直接调用bar。如果有一些R技巧,那么subdivisions参数将被遇到的第一个集成函数忽略,但对第二个集成函数可用,将是非常好的。

我最好的解决方法是为integrate编写一个使用参数SUBDIVISIONS的包装器,然后从bar调用包装器。如果没有更好的答案,我将发布该解决方案。

1 个答案:

答案 0 :(得分:1)

参数subdivisions不会从integrate传递,因为它是integrate的实际命名参数(仅...中的参数)将传递给f:

> integrate
# function (f, lower, upper, ..., subdivisions = 100L, rel.tol = .Machine$double.eps^0.25, 
#    abs.tol = rel.tol, stop.on.error = TRUE, keep.xy = FALSE, 
#    aux = NULL)

一种不需要更改bar的可能解决方案是在bar内为integrateBar写一个包装。我有两种变体:

变种1: 如果要将...中的参数传递给integrate的外部调用和内部调用,那就是这样:

integrateBar = function(xStart, xEnd, xMax, ..., fun) {

    argsExtra <- list(...)

    # A wrapper function for bar:
    # Note that the argument ... is necessary, although the function does not use
    # it. This is because, we still pass ... to the call to integrate below. 
    CallBarOnFun <- function(xVals, xMax, ...) {
      do.call(bar, c(list(xVals, xMax), argsExtra, list(fun=fun)))
    }

    aMatrix = cbind(xStart, xEnd)
    result =
      apply(
        aMatrix,
        1,
        function(xRange) {
            integrate(CallBarOnFun, xRange[1], xRange[2], xMax, ...)$value
        } 
      )
    return(result)
}

变体2:如果仅要将...中的参数传递给内部调用:

integrateBar = function(xStart, xEnd, xMax, ..., fun) {
    argsExtra <- list(...)

    CallBarOnFun <- function(xVals, xMax) {
        do.call(bar, c(list(xVals, xMax), argsExtra, list(fun=fun)))
    }

    aMatrix = cbind(xStart, xEnd)
    result =
      apply(
         aMatrix,
         1,
         function(xRange) {
             integrate(CallBarOnFun, xRange[1], xRange[2], xMax)$value
         } 
       )
    return(result)
}