gpt4 book ai didi

r - R中另一个函数的非标准评估

转载 作者:行者123 更新时间:2023-12-03 12:47:47 25 4
gpt4 key购买 nike

这是Hadley的高级R书中的一个示例:

sample_df <- data.frame(a = 1:5, b = 5:1, c = c(5, 3, 1, 4, 1))

subset2 <- function(x, condition) {
condition_call <- substitute(condition)
r <- eval(condition_call, x, parent.frame())
x[r, ]
}

scramble <- function(x) x[sample(nrow(x)), ]

subscramble <- function(x, condition) {
scramble(subset2(x, condition))
}

subscramble(sample_df, a >= 4)
# Error in eval(expr, envir, enclos) : object 'a' not found


哈德利解释说:


你知道问题出在哪里吗? condition_call包含表达式条件。因此,当我们评估condition_call时,它也会同时评估条件,其值a> =4。但是,由于父环境中没有称为a的对象,因此无法计算。


我知道父环境中没有 a,但是x中的 eval(condition_call, x, parent.frame()) evals conditional_call(用作环境的data.frame)由 parent.frame()包围。只要x中有一个名为 a的列,为什么会有任何问题?

最佳答案

tl; dr
当从subset2()内部调用subscramble()时,
condition_call的值是符号condition(而不是
调用a >= 4直接调用时产生的结果)。 subset()
调用eval()首先在condition中搜索envir=x
data.frame sample_df)。在此处找不到它,它随后在enclos=parent.frame()中搜索,在其中确实找到了一个名为
condition
该对象是一个promise对象,其表达槽为
a >= 4,评估环境为.GlobalEnv。除非
a中找到名为.GlobalEnv的对象,或者在搜索中更进一步的对象
路径,对承诺的评估然后失败,并显示观察到的消息
Error in eval(expr, envir, enclos) : object 'a' not found

详细说明
发现问题所在的一种好方法是插入一个
browser()直接在subset2()所在行之前调用
失败。这样,我们可以直接或间接地(从
在另一个函数中),并检查为什么它在第一种情况下成功,并且
在第二次失败。

subset2 <- function(x, condition) {
condition_call <- substitute(condition)
browser()
r <- eval(condition_call, x, parent.frame()) ## <- Point of failure
x[r, ]
}


直接调用subset2()
当用户直接致电 subset2()时,
condition_call <- substitute(condition)condition_call分配一个“呼叫”对象
包含未评估的呼叫 a >= 4。该呼叫被传递到
eval(expr, envir, enclos),它的第一个参数是
计算结果为 callname
expression。到目前为止,一切都很好。
subset2(sample_df, a >= 4)
## Called from: subset2(sample_df, a >= 4)
Browse[1]> is(condition_call)
## [1] "call" "language"
Browse[1]> condition_call
## a >= 4

eval()现在开始工作,搜索任何符号的值
包含在 expr=condition_call中,然后包含在 envir=x中,然后(如果
(必需)在 enclos=parent.frame()及其周围环境中。在
在这种情况下,它将在 a中找到符号 envir=x(以及符号 >=
package:base中)并成功完成评估。
Browse[1]> ls(x)
## [1] "a" "b" "c"
Browse[1]> get("a", x)
## [1] 1 2 3 4 5
Browse[1]> eval(condition_call, x, parent.frame())
## [1] FALSE FALSE FALSE TRUE TRUE


从subscramble()内调用subset2()
subscramble()正文中, subset2()的调用方式如下:
subset2(x, condition)。赶了出来,那个电话真的是等效的
subset2(x=x, condition=condition)。因为它提供了
参数(即,传递给名为的形式参数的值
condition)是表达式 condition
condition_call <- substitute(condition)condition_call分配符号对象 condition。 (了解这一点是准确了解嵌套调用如何失败的关键。)
由于 eval()很高兴将符号(也称为“名称”)作为其第一个
争论,到目前为止再好。
subscramble(sample_df, a >= 4)
## Called from: subset2(x, condition)
Browse[1]> is(condition_call)
## [1] "name" "language" "refObject"
Browse[1]> condition_call
## condition

现在 eval()开始搜索未解析的符号
conditionenvir=x中没有列(data.frame sample_df
匹配,因此将其移至 enclos=parent.frame()
复杂的原因,结果证明是环境
subscramble()调用的框架。在那里,它确实找到了
一个名为 condition的对象。
Browse[1]> ls(x)
## [1] "a" "b" "c"
Browse[1]> ls(parent.frame()) ## Aha! Here's an object named "condition"
## [1] "condition" "x"

作为重要的一点,事实证明,在调用 condition的环境上方的调用堆栈上有几个名为 browser()的对象。
Browse[1]> sys.calls()
# [[1]]
# subscramble(sample_df, a >= 4)
#
# [[2]]
# scramble(subset2(x, condition))
#
# [[3]]
# subset2(x, condition)
#
Browse[1]> sys.frames()
# [[1]]
# <environment: 0x0000000007166f28> ## <- Envt in which `condition` is evaluated
#
# [[2]]
# <environment: 0x0000000007167078>
#
# [[3]]
# <environment: 0x0000000007166348> ## <- Current environment


## Orient ourselves a bit more
Browse[1]> environment()
# <environment: 0x0000000007166348>
Browse[1]> parent.frame()
# <environment: 0x0000000007166f28>

## Both environments contain objects named 'condition'
Browse[1]> ls(environment())
# [1] "condition" "condition_call" "x"
Browse[1]> ls(parent.frame())
# [1] "condition" "x"

要检查由 condition找到的 eval()对象( parent.frame()中的一个对象,它原来是 subscramble()的评估框架)需要特别注意。我用 recover()
pryr::promise_info()如下所示。
该检查显示 condition是一个诺言,其表达槽为 a >= 4并且其
环境是 .GlobalEnv。至此,我们对 a的搜索进展顺利
过去的 sample_df(将找到 a的值),因此对
表达式槽失败(除非在 a中找到了名为 .GlobalEnv的对象,或者
搜索路径上方的其他位置)。
Browse[1]> library(pryr) ## For is_promise() and promise_info()  
Browse[1]> recover()
#
# Enter a frame number, or 0 to exit
#
# 1: subscramble(sample_df, a >= 4)
# 2: #2: scramble(subset2(x, condition))
# 3: #1: subset2(x, condition)
#
Selection: 1
# Called from: top level
Browse[3]> is_promise(condition)
# [1] TRUE
Browse[3]> promise_info(condition)
# $code
# a >= 4
#
# $env
# <environment: R_GlobalEnv>
#
# $evaled
# [1] FALSE
#
# $value
# NULL
#
Browse[3]> get("a", .GlobalEnv)
# Error in get("a", .GlobalEnv) : object 'a' not found


另有证据表明已找到承诺对象 condition
enclos=parent.frame()中,可以将 enclos指向其他更远的地方
搜索路径,以便在评估 parent.frame()时跳过 condition_call。当一个
subscramble()再次失败,但是这次有一条消息
找不到 condition本身。
## Compare
Browse[1]> eval(condition_call, x, parent.frame())
# Error in eval(expr, envir, enclos) (from #4) : object 'a' not found

Browse[1]> eval(condition_call, x, .GlobalEnv)
# Error in eval(expr, envir, enclos) (from #4) : object 'condition' not found

关于r - R中另一个函数的非标准评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30563745/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com