5

I'm reading the AdvancedR by Hadley and am testing the following code on this URL

subset2 = function(df, condition){
  condition_call = eval(substitute(condition),df )  

  df[condition_call,]
}

df = data.frame(a = 1:10, b = 2:11)

condition = 3

subset2(df, a < condition)

Then I got the following error message:

Error in eval(substitute(condition), df) : object 'a' not found

I read the explanation as follows but don't quite understand:

If eval() can’t find the variable inside the data frame (its second argument), it looks in the environment of subset2(). That’s obviously not what we want, so we need some way to tell eval() where to look if it can’t find the variables in the data frame.

In my opinion, while "eval(substitute(condition),df )", the variable they cannot find is condition, then why object "a" cannot be found?

On the other hand, why the following code won't make any error?

subset2 = function(df, condition){
  condition_call = eval(substitute(condition),df )  

  df[condition_call,]
}

df = data.frame(a = 1:10, b = 2:11)

y = 3

subset2(df, a < y)
4

2 回答 2

3

这个更精简的例子可能会让你更容易看到 Hadley 的例子中发生了什么。首先要注意的是,该符号condition在此处以四种不同的角色出现,我已用编号注释对每个角色进行了标记。

                              ## Role of symbol `condition`

f <- function(condition) {    #1 -- formal argument
    a <- 100
    condition + a             #2 -- symbol bound to formal argument
}

condition <- 3                #3 -- symbol in global environment

f(condition = condition + a)  #4 -- supplied argument (on RHS)
## Error in f(condition = condition + a) (from #1) : object 'a' not found

要理解的另一件重要的事情是在调用函数的评估框架中搜索提供的参数中的符号(这里是condition = condition + aat的右侧部分)。#4第 4.3.3 节R 语言定义的参数评估:

关于函数参数的评估,最重要的事情之一是提供的参数和默认参数的处理方式不同。提供给函数的参数在调用函数的评估框架中进行评估。函数的默认参数在函数的评估框架中评估。

在上面的例子中,调用的评估框架f()是全局环境,.GlobalEnv.

一步一步来,当你调用(condition = condition + a). 在函数求值期间,R 遇到condition + a函数体 (at #2) 中的表达式。它搜索 和 的值,acondition找到一个本地分配的符号a。它发现符号condition绑定到名为condition(at #1) 的形式参数。在函数调用期间提供的形式参数的值是condition + a(at #4)。

如 R 语言定义中所述,表达式中符号的值是condition + a在调用函数的环境中搜索的,这里是全局环境。由于全局环境包含一个名为condition(分配在#3)的变量,但没有名为的变量a,它无法计算表达式condition + a(在#4),并且失败并出现您看到的错误。

于 2018-08-06T04:46:40.853 回答
2

我想添加一些细节,以防有人偶然发现这个问题。有问题的行是

condition_call = eval(substitute(condition),df )  
  • replace() 函数中的条件对象是一个promise 对象,它的表达式槽是“a < 条件”,substitute(condition) 接受表达式并返回一个表达式为“a < 条件”的调用对象。

  • 然后 eval() 函数开始评估 df 环境中的“a <条件”。它的目标是找到acondition

    • a在 df 中成功找到,这不是 bug 产生的地方
    • 然后 R 开始在 df 中搜索条件并且找不到它。
    • 于是 R 上升到子集 2 的执行环境,并在执行环境中找到条件。
    • 它找到的变量实际上是前面提到的promise对象,表达式槽为“a <条件”。
    • 要评估这个表达式,R 必须再次找到a,现在它无法再找到 a,因为它已经通过了 df 环境。这是真正产生错误的部分。

在这里总结一下问题:

  • R 确实在 df 中找到一次。
  • 当 R 尝试查找条件然后 R 将 promise 对象条件而不是外部分配的4作为参数并尝试评估它时,就会出现错误。
  • 然后R遇到了问题:
    • 它试图评估“a <条件”,但它在subset2() 的执行环境或全局环境中都找不到a 。

对于我的第二个示例,R 在执行环境中找不到 y,然后在 subset2() 的调用环境中找到 y 为 4,不会产生任何错误。在这种情况下,y 的名称与 promise 对象条件不同,R 不会尝试评估“a < y”并且不会产生错误。

于 2018-08-11T18:50:30.220 回答