`do.call` 使用合格的命令

huangapple go评论75阅读模式
英文:

`do.call` using qualified commands

问题

I want to apply a qualified command utilizing do.call, but get an error message.
('qualified' here means: qualified with a package name.)

fn = function(x) sin(x[1]) + cos(x[2])
x0 = c(pi/2, pi/2)

# qualified command works, but not with `do.call` !
numDeriv::hessian(func = fn, x = x0)
##               [,1]          [,2]
## [1,] -1.000000e+00 -5.910744e-13
## [2,] -5.910744e-13  1.063389e-15

do.call("numDeriv::hessian", list(func = fn, x = x0))
## Error in `numDeriv::hessian`(f = function (x)  : 
##   could not find function "numDeriv::hessian"

# loading the library first works too
library(numDeriv)
do.call("hessian", list(func = fn, x = x0))
##               [,1]          [,2]
## [1,] -1.000000e+00 -5.910744e-13
## [2,] -5.910744e-13  1.063389e-15

How can I make this work without explicitly loading the library?

EDIT: In the comments it is suggested to delete the quotes. This is true.
Unfortunately, I have to assemble the command from package and function name.
(Sorry, I didn't mention this in the original post.)

So the only way that solves my real 'challenge' is the one by Gabor:

fn = function(x) sin(x[1]) + cos(x[2])
x0 = c(pi/2, pi/2)

lib <- "numDeriv"
routine <- "hessian"

do.call(routine, list(func = fn, x = x0),
        envir = asNamespace(lib))
##               [,1]          [,2]
## [1,] -1.000000e+00 -5.910744e-13
## [2,] -5.910744e-13  1.063389e-15

Thanks Gabor, very nice. I'd give you the credits if you formulate it as an official answer.

<details>
<summary>英文:</summary>

I want to apply a qualified command utilizing `do.call`, but get
an error message.\
(&#39;qualified&#39; here means: qualified with a package name.)

    fn = function(x) sin(x[1]) + cos(x[2])
    x0 = c(pi/2, pi/2)
    
    # qualified command works, but not with `do.call` !
    numDeriv::hessian(func = fn, x = x0)
    ##               [,1]          [,2]
    ## [1,] -1.000000e+00 -5.910744e-13
    ## [2,] -5.910744e-13  1.063389e-15

    do.call(&quot;numDeriv::hessian&quot;, list(func = fn, x = x0))
    ## Error in `numDeriv::hessian`(f = function (x)  : 
    ##   could not find function &quot;numDeriv::hessian&quot;

    # loading the library first works too
    library(numDeriv)
    do.call(&quot;hessian&quot;, list(func = fn, x = x0))
    ##               [,1]          [,2]
    ## [1,] -1.000000e+00 -5.910744e-13
    ## [2,] -5.910744e-13  1.063389e-15

How can I make this work without explicitly loading the library?

EDIT: In the comments it is suggested to delete the quotes. This is true.
Unfortunately, I have to assemble the command from package and function name.\
(Sorry, I didn&#39;t mention this in the original post.)

So the only way that solves my real &#39;challenge&#39; is the one by Gabor:

    fn = function(x) sin(x[1]) + cos(x[2])
    x0 = c(pi/2, pi/2)
    
    lib &lt;- &quot;numDeriv&quot;
    routine &lt;- &quot;hessian&quot;

    do.call(routine, list(func = fn, x = x0),
            envir = asNamespace(lib))
    ##               [,1]          [,2]
    ## [1,] -1.000000e+00 -5.910744e-13
    ## [2,] -5.910744e-13  1.063389e-15

Thanks Gabor, very nice. I&#39;d give you the credits if you formulate it as an official answer.


</details>


# 答案1
**得分**: 3

问题在于`numDeriv::hessian`不是一个函数的名称,而是一个对`::`的函数调用,用于从`numDeriv`包中获取名为`hessian`的函数。因此,你可以在调用之前自己执行这个操作,例如:

```R
hessian <- numDeriv::hessian
do.call("hessian", list(func = fn, x = x0))

或者(正如@MikaelJagan在评论中所提到的),传递实际的函数而不是它的名称:

do.call(numDeriv::hessian, list(func = fn, x = x0))

这两种方法在回溯信息中会稍微有些不同;我的第一个建议将显示为hessian(func = ...,而第二个将显示为(function (func, x, method = "Richardson", method.args = list(), ...) UseMethod("hessian"))(func = . 但结果将是相同的。

@G.Grothendieck在评论中提供了另一个解决方案:

do.call("hessian", list(func = fn, x = x0), envir = asNamespace("numDeriv"))

这意味着构建函数调用,然后在numDeriv命名空间中进行评估。一开始我对它有所怀疑,因为

hessian(func = fn, x = x0)

在该命名空间中不一定会正确评估(因为fnx0在那里没有定义),但它不是尝试评估这个。它首先替换了fnx0的值,然后评估了:

hessian(func = function(x) sin(x[1]) + cos(x[2]), 
        x = c( 1.570796, 1.570796) )

这也可以正常工作。

英文:

The problem is that numDeriv::hessian is not the name of a function, it's a function call to :: to get the function named hessian from the numDeriv package. So you could do that yourself ahead of the call, e.g.

hessian &lt;- numDeriv::hessian
do.call(&quot;hessian&quot;, list(func = fn, x = x0))

or (as @MikaelJagan said in a comment) pass the actual function instead of its name:

do.call(numDeriv::hessian, list(func = fn, x = x0))

These will appear slightly differently in tracebacks; my first suggestion would display as hessian(func = ..., while the second would display as (function (func, x, method = &quot;Richardson&quot;, method.args = list(), ...) UseMethod(&quot;hessian&quot;))(func = . But the results will be the same.

@G.Grothendieck gave another solution in a comment:

do.call(&quot;hessian&quot;, list(func = fn, x = x0), envir = asNamespace(&quot;numDeriv&quot;))

This says to construct the function call, then evaluate it in the numDeriv namespace. I was suspicious of it at first, because

hessian(func = fn, x = x0)

wouldn't necessarily evaluate properly in that namespace (since fn and x0 aren't defined there), but that's not what it tries to evaluate. It substitutes the values for fn and x0 first, and then evaluates

hessian(func = function(x) sin(x[1]) + cos(x[2]), 
x = c( 1.570796, 1.570796) )

This also works fine.

huangapple
  • 本文由 发表于 2023年6月16日 02:09:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76484425.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定