R中的动态范围问题

时间:2018-08-06 01:06:36

标签: r eval dynamic-scope

我正在阅读Hadley的AdvancedR,并正在此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)

然后我收到以下错误消息:

  

eval(substitute(condition),df)中的错误:找不到对象'a'

我阅读了以下说明,但不太了解:

  

如果eval()在数据框内(第二个参数)找不到该变量,则它将在subset2()的环境中查找。显然这不是我们想要的,因此我们需要某种方法来告诉eval()如果找不到数据框中的变量,该在哪里查看。

我认为,尽管“ eval(substitute(condition),df)”却找不到条件变量,那么为什么找不到对象“ a”?

另一方面,为什么下面的代码不会出错?

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)

2 个答案:

答案 0 :(得分:2)

这个更精简的示例可能使您更容易了解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 + a#4的右侧部分)中的符号。来自R语言定义的Section 4.3.3 Argument Evaluation

  

关于函数参数评估的最重要的事情之一就是对提供的参数和默认参数的处理方式有所不同。提供给函数的参数在调用函数的求值框架中求值。函数的默认参数在函数的评估框架中评估。

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

逐步进行,这是您致电(condition = condition + a)时发生的情况。在函数求值期间,R在函数体中(在condition + a处遇到表达式#2。它搜索acondition的值,并找到本地分配的符号a。它发现符号condition已绑定到名为condition的形式参数(在#1处)。在函数调用期间提供的 that 形式参数的值为condition + a(在#4处)。

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

答案 1 :(得分:0)

我想添加一些详细信息,以防有人偶然发现此问题。有问题的行是

condition_call = eval(substitute(condition),df )  
  • 替代()函数中的条件对象是一个promise对象,其表达式槽为“一个<条件”,而alternate(condition)接受表达式并返回带有表达式的调用对象为“一个<条件”。

  • 然后,eval()函数开始在df环境中评估“ a <条件”。其目标是同时找到 a 条件

      在df中成功找到
    • a 这不是生成错误的地方
    • 然后R开始在df中搜索条件并找不到它。
    • 因此,R进入子集2的执行环境,并在执行环境中查找条件。
    • 它找到的变量实际上是前面提到的promise对象,表达式槽为“ a
    • 要计算此表达式,R必须再次找到 a ,现在它再也找不到了,因为它已通过df环境。 这是真正产生错误的部分。

在这里总结问题:

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

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