在R中的另一个函数中定义和调用函数有什么好处?

FXQ*_*der 8 performance r function

方法1

f1 <- function(x)
{
    # Do calculation xyz ....

    f2 <- function(y)
    {
        # Do stuff...
        return(some_object)
    }

    return(f2(x))
}
Run Code Online (Sandbox Code Playgroud)

方法2

f2 <- function(y)
{
    # Do stuff...

    return(some_object)
}

f3 <- function(x)
{
    # Do calculation xyz ....
    return(f2(x))
}
Run Code Online (Sandbox Code Playgroud)

假设f1并且f3两者都进行相同的计算并给出相同的结果.

使用方法1,呼叫,方法2,呼叫是否有任何明显的优势?f1()f3()

在以下情况下某种方法更有利:

  • 大数据传入和/或传出 f2

  • 速度是一个大问题.例如,f1f3在模拟中反复调用.

(方法1似乎在包中很常见,在另一个内部定义)

使用方法的一个优点f1是,f2将不存在之外f1,一旦f1完成了被称为(并f2仅在被称为f1f3).

Bro*_*ieG 7

定义f2内部的好处f1:

  • f2只在内部可见f1,如果f2仅用于内部有用f1,虽然在包命名空间内这是有争议的,因为f2如果你在外面定义它就不会导出
  • f2可以访问f1其中的变量,这可能被视为好事或坏事:
    • 好的,因为你不必通过函数接口传递变量,你可以<<-用来实现memoization等东西.
    • 不好,出于同样的原因......

缺点:

  • f2需要在每次调用时重新定义f1,这会增加一些开销(不是很多开销,但绝对有)

数据大小无关紧要,因为除非在任一情况下修改数据,否则R不会复制数据.如缺点所述,定义f2外部f1应该更快一些,特别是如果您多次重复一个相对较低的开销操作.这是一个例子:

> fun1 <- function(x) {
+   fun2 <- function(x) x
+   fun2(x)
+ }
> fun2a <- function(x) x
> fun3 <- function(x) fun2a(x)
> 
> library(microbenchmark)
> microbenchmark(
+   fun1(TRUE), fun3(TRUE)
+ )
Unit: nanoseconds
       expr min    lq median    uq   max neval
 fun1(TRUE) 656 674.5  728.5 859.5 17394   100
 fun3(TRUE) 406 434.5  480.5 563.5  1855   100
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们保存为250ns(编辑:区别其实为200ns;无论你相信与否额外的一套{}fun1有代价的另一个为50ns).不多,但如果内部功能更复杂或者您重复多次功能,可以加起来.


csg*_*pie 5

您通常会使用方法2.一些例外情况

  1. 功能关闭:

    f = function() {
        counter = 1
        g = function() {
            counter <<- counter + 1
            return(counter)
        }
     }
     counter = f()
     counter()
     counter()
    
    Run Code Online (Sandbox Code Playgroud)

    函数闭包使我们能够记住状态.

  2. 有时仅定义函数是很方便的,因为它们仅在一个地方使用.例如,在使用时optim,我们经常调整现有的功能.例如,

    pdf = function(x, mu) dnorm(x, mu, log=TRUE)
    f = function(d, lower, initial=0) {
      ll = function(mu) {
        if(mu < lower) return(-Inf)
        else -sum(pdf(d, mu))
      }
      optim(initial, ll)
    }
    
    f(d, 1.5)
    
    Run Code Online (Sandbox Code Playgroud)

    ll函数使用数据集d和下限.这很方便,因为这可能是我们使用/需要该ll功能的唯一时间.