【问题标题】:exists and sapply: why are these functions different?存在和应用:为什么这些功能不同?
【发布时间】:2015-06-17 00:50:51
【问题描述】:

为什么下面的fngn这两个函数不一样?我不认为他们应该是,但我一定是错过了什么。

vars <- letters[1:10]
a <- b <- 1
fn <- function (d) {
    sapply( vars, exists )
}
gn <- function (d) {
    sapply( vars, function (x) { exists(x) } )
}
fn(d=2)
#    a     b     c     d     e     f     g     h     i     j 
# TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE 
gn(d=2)
#    a     b     c     d     e     f     g     h     i     j 
# TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE 
exists("i")
# [1] FALSE

有两个区别:

  1. gn(d=2)d 存在,但为什么 fn(d=2) 不存在?
  2. fn(d=2) 表示 i 存在,而 gn(d=2) 不存在。这令人费解,因为我没有在任何地方定义i

注意:这是在 R 版本 3.2.0 上,第二个行为似乎是该版本的新行为(见下文)。

【问题讨论】:

  • 两者都为我返回FALSEi。你能分享你看到的输出吗?听起来你可能已经在不同的环境中定义了你的函数,这个例子实际上并没有重现问题。
  • 我遇到了与 OP rm(list = ls()); ls() character(0); exists('i') [1] FALSE, sapply('i', exists) i TRUE 相同的异常情况
  • sapply 很可能会临时创建一个对象 i 并在评估后将其丢弃。但是按照这个逻辑,所有vars 输入都应该返回TRUE
  • @plafort 你运行的是什么版本的 R?
  • @plafort 是的。我两个都错了。我在 R 3.1.0 上测试过。

标签: r scope sapply


【解决方案1】:

为什么i 不一样...

R 3.2 中似乎发生了变化。一个索引变量ilapplyadded to the current environment(这是sapply 实际调用的)。这与新行为一起强制评估传递给您正在应用的函数的参数。这意味着您现在可以访问循环中当前迭代的索引。

fngn 行为不同的原因是 exists() 在调用它的环境中查找。在fn 的情况下,这是创建此i 变量的环境。对于gn,它正在查看您的匿名函数的环境。当 R 在本地环境中找不到符号时,它会根据定义函数的位置而不是调用它们的位置来搜索环境。这意味着 R 将找不到 i 变量,因为您的匿名函数是在不存在 i 变量的地方定义的。

我们可以编写一个小辅助函数来更容易地获取当前索引。

idx <- function() get("i", parent.frame(2))
sapply(letters[1:3], function(x) paste(idx(), x))
#     a     b     c 
# "1 a" "2 b" "3 c"

据我所知,这是目前未记录的行为。它可能会在 R 的未来版本中发生变化。

为什么d 不一样...

d 变量的差异是一个更直接的范围问题。 R 再次创建了一个新环境,用于调用函数exists。此环境的父级是基础环境。因此,当您调用exists 时,它会查看调用它的位置(这是存在i 的环境),并且由于它没有在那里找到d,它会搜索下一个父环境,即基础环境。从不搜索当前函数环境。您可以使用

显式搜索当前环境
fn <- function (d) {
    sapply( vars, exists, where=environment() )
}
fn(d=2)
#    a     b     c     d     e     f     g     h     i     j 
# TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE 

有关 R 环境的更多信息,我建议您阅读Environments section of Advanced R

【讨论】:

  • 它们都与范围有关,只是i 更加令人困惑,因为不清楚它为什么存在于sapply 的范围内? (但是,很高兴知道i...)
  • 感谢您的解释!
【解决方案2】:

重要的区别是“d”的值,即调用中形式变量的名称。 . exists 函数的默认设置是查看“上方”而不是“内部”。在第一个实例中,.GlobalEnv 中没有以“d”命名的实体,这是调用函数的地方。在第二种情况下,周围环境中有一个d(作为名称)。

查找“i”或“c”的人会找到函数c 或for 循环的索引。 (索引变量在 for 循环结束时保持不变。)

似乎“i”值差异仅存在于我在这台机器上没有看到的最新版本中,因为我当前的操作系统版本在 3.1.3 时已达到最大值。在当前会话的 for 循环中使用“i”作为索引变量(或正在使用早期保存的环境)的人也可能发生这种情况。

【讨论】:

  • 你还没有解决为什么函数exists('i')返回false而sapply('i', exists)不返回?
  • ?get 声明默认查看位置是pos = -1,并且“默认‘-1’表示调用‘get’的当前环境。”这看起来不像“在上面,不在里面”?
  • @petrelharp -1 表示搜索将沿着整个搜索路径继续,而不是被限制在当前路径“之上”的特定环境中。
  • @plafort:因为我没看出有什么不同。
【解决方案3】:

关于i,我无法重现它。但我将尝试解释其他差异,首先是两个函数都可以找到的c,以及只有gn() 可以找到的d

这两个函数都找到了c,因为它们正在寻找基函数c

现在对于d,R 是词法范围的。你可能想看看这个问题Environments in R, mapply and get。因此,在第一个函数fn() 中,exists 不会在fn() 的本地环境中查找d,而是在全局环境中查找(并且那里没有d)。

但是请注意,在gn() 中,您将使用exists() 的函数定义为gn() 中的匿名函数。看:

gn <- function (d) {
    sapply( vars, function (x) { exists(x) } ) # defined anon function
}

所以gn()的环境是匿名函数function (x) { exists(x) }的父环境。这就是为什么它在gn 内部搜索并找到本地参数d,返回TRUE

【讨论】:

    【解决方案4】:

    这是奇怪的行为。我相信有一个合理的解释。这是一个全新的 R 会话。这次我什至没有使用 RStudio,它会产生相同的输出。

    R version 3.2.0 (2015-04-16) -- "Full of Ingredients"
    Copyright (C) 2015 The R Foundation for Statistical Computing
    
    Type 'demo()' for some demos, 'help()' for on-line help, or
    'help.start()' for an HTML browser interface to help.
    Type 'q()' to quit R.
    
    > exists('i')
    [1] FALSE
    > sapply('i', exists)
       i 
    TRUE 
    

    更奇怪的行为:

    > lapply('i', exists)
    [[1]]
    [1] TRUE
    
    > vapply('i', exists, logical(1))
       i 
    TRUE 
    > tapply('i', 'i', exists)
       i 
    TRUE 
    > mapply(exists, list('i'))
    [1] FALSE
    > rapply(list('i'), exists)
    [1] FALSE
    > exists('i')
    [1] FALSE
    > ls()
    character(0)
    

    mapplyrapply 都返回 FALSE。它们都需要列表作为参数。这可能与它有关。也许其他应用函数在 R 中的某些环境中拾取了一些裸函数和一些应用函数没有的东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-07
      • 2016-01-19
      • 2022-08-09
      • 1970-01-01
      • 2019-08-18
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      相关资源
      最近更新 更多