如何将调用对象传递给do.call。

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

How to pass call object into do.call

问题

给定一个分类函数 ranger,我想从其定义中使用 formals 获取所有参数及其默认值。然后,我想更改一些默认值,并将它们作为参数使用 do.call

library(ranger)
# 获取 "ranger" 函数的所有参数及其默认值
lParams <- formals(ranger)
lParams <- as.list(lParams)

# 替换一些默认值以进行测试
lParams$formula <- as.formula("Species~.")
lParams$data <- substitute(iris)
lParams[[...]] <- NULL

#lParams[["sample.fraction"]] <- NULL

do.call("ranger", lParams)

但是它不起作用:

Error in as.logical(test) : 
  cannot coerce type 'closure' to vector of type 'logical'

似乎 sample.fraction 元素是错误的原因。它是一个 call 对象。如果我使用以下方法删除该元素:

lParams[["sample.fraction"]] <- NULL

...那么我的代码就可以工作了。

我不知道如何处理这个对象以防止出现此错误。

英文:

Giving a classification function ranger, I want to get all the parameters with their default values from its definition using formals. Then, I want to change some default values and use them as parameter with do.call

library(ranger)
# Getting all the parameters for &quot;ranger&quot; function with their default values
lParams&lt;-formals(ranger)
lParams&lt;-as.list(lParams)

# Replace some default values for testing purposes
lParams$formula&lt;-as.formula(&quot;Species~.&quot;)
lParams$data&lt;-substitute(iris)
lParams[[&quot;...&quot;]]&lt;-NULL

#lParams[[&quot;sample.fraction&quot;]]&lt;-NULL

do.call(&quot;ranger&quot;,lParams)

But it does not work:

Error in as.logical(test) : 
  cannot coerce type &#39;closure&#39; to vector of type &#39;logical&#39;

It seems sample.fraction element is the cause of the error. It is a call object. If I remove that element using:

lParams[[&quot;sample.fraction&quot;]]&lt;-NULL

...so, my code works.

I do not know how to treat this object to prevent this error.

答案1

得分: 4

do.call 受到与调用函数时相同的限制。通过获取所有形式参数并重新添加它们,本质上就是在调用以下函数:

ranger(formula = Species ~ ., data = iris, num.trees = 500, 
    mtry = NULL, importance = &quot;none&quot;, write.forest = TRUE, probability = FALSE, 
    min.node.size = NULL, max.depth = NULL, replace = TRUE, sample.fraction = ifelse(replace, 
        1, 0.632), case.weights = NULL, class.weights = NULL, 
    splitrule = NULL, num.random.splits = 1, alpha = 0.5, minprop = 0.1, 
    split.select.weights = NULL, always.split.variables = NULL, 
    respect.unordered.factors = NULL, scale.permutation.importance = FALSE, 
    local.importance = FALSE, regularization.factor = 1, regularization.usedepth = FALSE, 
    keep.inbag = FALSE, inbag = NULL, holdout = FALSE, quantreg = FALSE, 
    oob.error = TRUE, num.threads = NULL, save.memory = FALSE, 
    verbose = TRUE, seed = NULL, dependent.variable.name = NULL, 
    status.variable.name = NULL, classification = NULL, x = NULL, 
    y = NULL)

如果你运行上述代码,会得到完全相同的错误。让我们创建一个简化的示例:

foo &lt;- function(x, y=x+5) {
   x*y
}
foo(5)
# [1] 50

如果我尝试相同的技巧,我会得到以下错误:

params &lt;- as.list(formals(foo))
params$x &lt;- 5
do.call(&quot;foo&quot;, params)
# Error in foo(x = 5, y = x + 5) : object &#39;x&#39; not found

因为我不能调用以下方式:

foo(x = 5, y = x + 5)

默认的延迟参数值有点特殊。你无法传递任何值给它们,使其表现得像你留下了该值。这是因为你传递的值在不同的环境中进行求值,而不同于默认参数。你得到的特定错误消息" cannot coerce type 'closure' to vector of type 'logical'"是因为 replace 在全局环境中是一个函数,但在函数内部具有不同的含义。

如果你想避免潜在问题,最好不要以所有形式参数开始。或者至少过滤掉任何调用或符号。你可以使用以下方式进行过滤:

lParams &lt;- lParams[!sapply(lParams, function(x) any(c(&quot;call&quot;,&quot;symbol&quot;) %in% class(x)))]
英文:

do.call is limited by the same restrictions you are when calling a function. By taking all the formals and readding them, you are essentially calling

ranger(formula = Species ~ ., data = iris, num.trees = 500, 
    mtry = NULL, importance = &quot;none&quot;, write.forest = TRUE, probability = FALSE, 
    min.node.size = NULL, max.depth = NULL, replace = TRUE, sample.fraction = ifelse(replace, 
        1, 0.632), case.weights = NULL, class.weights = NULL, 
    splitrule = NULL, num.random.splits = 1, alpha = 0.5, minprop = 0.1, 
    split.select.weights = NULL, always.split.variables = NULL, 
    respect.unordered.factors = NULL, scale.permutation.importance = FALSE, 
    local.importance = FALSE, regularization.factor = 1, regularization.usedepth = FALSE, 
    keep.inbag = FALSE, inbag = NULL, holdout = FALSE, quantreg = FALSE, 
    oob.error = TRUE, num.threads = NULL, save.memory = FALSE, 
    verbose = TRUE, seed = NULL, dependent.variable.name = NULL, 
    status.variable.name = NULL, classification = NULL, x = NULL, 
    y = NULL)

And you get the exact same error if you run that. Let's create a simplified example

foo &lt;- function(x, y=x+5) {
   x*y
}
foo(5)
# [1] 50

If I tried the same trick, I would get

params &lt;- as.list(formals(foo))
params$x &lt;- 5
do.call(&quot;foo&quot;, params)
# Error in foo(x = 5, y = x + 5) : object &#39;x&#39; not found

because I cannot call

foo(x =5, y=x+5)

Default lazy parameter values are kind of special. There's nothing you can pass to them that will behave like if you leave the value missing. That's because values you pass in are evaluated in a different environment than default parameters. The specific error you get " cannot coerce type 'closure' to vector of type 'logical'" is because replace is a function in the global enviroment, but has a different meaning within the function itself.

If you want to avoid potential problems, it's probably best not to start with all the formal arguments. Or at the very list filter out any calls or symbols. You could filter them out with

lParams &lt;- lParams[!sapply(lParams, function(x) any(c(&quot;call&quot;,&quot;symbol&quot;) %in% class(x)))]

huangapple
  • 本文由 发表于 2023年2月24日 10:27:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75552114.html
匿名

发表评论

匿名网友

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

确定