R:如何评估函数的形式(参数)?

R : How evaluate formals (arguments) of function?

我真的找遍了所有地方,但没有找到我的问题的答案:

广义问题:

我的问题:

我想获取 R 中任何函数的参数的计算时间。例如,让我们考虑一个函数:

foo <- function(x, arg1 = 2, arg2 = arg3[1], arg3 = rnorm(10^6)) {
  rnorm(10^7) # whatever time-consuming computation here
  arg3^2
  message("Too bad you had to launch the whole function !")
}

你会注意到困难的:

期望的输出:

> system.time(foo(x=1))
Too bad you had to launch the whole function !
       user      system      elapsed 
      1.835       0.000       1.573 

> solution.function(foo, list(x=1))
The answer is in reality much lower ! It takes only 0.2 sec to compute the arguments !

广义解

很简单,似乎 as.list(environment) 实际上评估了整个环境并且 return 是一个列表!

我的最终解决方案

感谢 Martin Morgan 的帮助,我想出了这个解决方案,非常简单,并且解决了问题的所有限制:

foo2 <- foo #Just copy/paste the function, before modifying it
body(foo2) <- quote(as.list(environment())

foo2(x=2) 将 return 函数的所有参数(已评估)、必需参数 (x) 以及默认参数 (arg1arg2, arg3)

您可以检查:system.time(foo2(x=1)) 将 return 0.2 seconds ...仅 rnorm(10^6) 启动。

目前我的工作区中确实有一个名为 'c' 的矢量和一个名为 'd' 的数据框,所以我从以下位置获得:

lapply( formals(foo), eval)
#---------
$a
[1] 2

$b
function (..., recursive = FALSE)  .Primitive("c")

$c
      a  b a2 b2
[1,]  1 NA  1 NA
[2,]  4 NA  4 NA
[3,]  9 NA  9 NA
[4,] 16 NA 16 NA
[5,] 25 NA 25 NA

$d
[1] 4

Warning messages:
1: In Ops.factor(left, right) : ‘^’ not meaningful for factors
2: In Ops.factor(left, right) : ‘^’ not meaningful for factors

这不完全是您 EvalFormals 返回的内容,但它似乎是我(一个经验丰富的 R 用户)所期望的。我不明白与测量执行时间的可能联系。

基本上是 hack,但复制你的函数

g = foo

用表达式替换函数体以计算每个参数,注意让错误继续存在

body(g) = quote(lapply(formals(), function(x) try(eval(x), TRUE))

或者也许

body(g) = quote(sapply(formals(), function(x) system.time(try(eval(x), TRUE))))

评价g()(第一版)

> g()
$a
[1] 2

$b
[1] 16

$c
[1] 16

$d
[1] 4

$e
[1] "Error in eval(expr, envir, enclos) : object 'unknown_variable' not found\n"
attr(,"class")
[1] "try-error"
attr(,"condition")
<simpleError in eval(expr, envir, enclos): object 'unknown_variable' not found>

R 具有惰性计算,因此这不是衡量函数内部和外部时间的好方法。例如,f = function(y=Sys.sleep(Inf)) 1 returns 立即而不是从不。

必须单独处理 ... 个参数。

受上述答案的启发,以防万一有人在他们的全局环境中也需要这些变量(例如,用于对函数进行故障排除)。

Troubleshoot_function = function(fn, ...)
{
  body(fn) = quote(expr = lapply(formals(), 
                                 FUN = function(x)
                                   {
                                   try(eval(x), TRUE)
                                   }
                                 )
                  )
  ex = fn(...)
  nm = names(ex)
  invisible(
    {
  lapply(X = 1:length(ex),
         FUN = function(i)
                 {
                 assign(x = nm[i],
                        value = ex[[i]],
                        envir = .GlobalEnv,
                        pos = -1
                        )
                 }
         )
    }
  )
}

#example
Troubleshoot_function(foo)
 ls()
[1] "arg1"                  "arg2"                  "arg3"                 
[4] "foo"                   "Troubleshoot_function" "x"      
arg1
[1] 2