subset_base是以r为基的subset()函数的简单形式.本例取自高级R第20.6.1章.

此函数本身运行良好:

subset_base <- function(data, rows) {
  rows <- substitute(rows)
  rows_val <- eval(rows, data, parent.frame())
  data[rows_val, , drop = FALSE]
}

my_df <- data.frame(x = 1:3)
  
subset_base(my_df, x == 1)
#>   x
#> 1 1

然而,当我们构建包装器函数apply_subset时,在该包装器函数中定义一些值zzz,并在subset_base上调用lapply()(在同一函数中),提供zzz作为参数,但找不到.

我想更好地理解为什么找不到zzz个.我的心理模型是这样的:lapply调用subset_base,而apply_subset调用subset_base.在subset_base中,我们计算提供的data.frame data中的rows参数,该参数将自动转换为环境.该环境由调用环境parent.frame()封装.这应该是lapply的执行环境.我想这个环境又是以lapply的调用环境为父的.这将是apply_subset的执行环境.但情况似乎并非如此,因为如果这是真的,那么应该找到zzz个.

apply_subset <- function(){
  zzz <- 2
  dfs <- list(data.frame(x = 1:3), data.frame(x = 4:6))
  lapply(dfs, FUN = subset_base, x == zzz)
}

apply_subset()
#> Error in eval(rows, data, parent.frame()): object 'zzz' not found

更奇怪的是,当我们从直接提供subset_base作为对象/函数名更改为调用lapply,并将其包装到匿名函数中时,可以找到zzz.

apply_subset2 <- function(){
  zzz <- 2
  dfs <- list(data.frame(x = 1:3), data.frame(x = 4:6))
  lapply(dfs, FUN = \(df) subset_base(df, x == zzz))
}

apply_subset2()
#> [[1]]
#>   x
#> 2 2
#> 
#> [[2]]
#> [1] x
#> <0 rows> (or 0-length row.names)

创建于2024-01-27,共reprex v2.0.2

我非常希望解释一下(1)调用堆栈中每个执行环境的父环境是什么,(2)为什么我认为它们是一致的,显然是错误的,以及(3)当对lapply的调用使用匿名函数时,为什么这种情况会改变.此外,如果知道(4)是否有任何方法可以在不使用匿名函数的情况下使lApply调用工作(Advanced R似乎建议(可能)唯一的解决方案是使用Rangs Quosures),那将是非常好的.

推荐答案

关键点是,如果我们相对于父帧来判断表达式,它将查看调用堆栈的一个级别,如果没有找到,将不会进一步查看调用堆栈,而是查看调用者为defined的环境,并递归地查看其祖先.

有了这个背景,我们可以回答以下问题:

(1) what the parent environments of each execution environment in the call stack are,

apply_subset运行时,函数subset_base被传递到lapply,然后lapply内的代码调用传递的subset_base,因此lapply内的执行环境是subset_base的父框架,而不是zzz所在的apply_subset内的执行环境. zzz不在lapply的执行环境中,因此它查看的下一个位置是lapply的父环境,其中lapplydefined(不在调用堆栈的更高位置). 在这种情况下,它在基本包中查找,但zzz也不在那里,然后它在全局环境中查找,搜索路径上的所有包都不在那里,但zzz也不在那里,因此出现错误.

(2) why my assumption that they align is, apparently, wrong, and

请参见上文.

(3) why this changes, when the call to lapply uses an anonymous function. Further it would be great to know, if

当匿名函数调用subset_base时,它在匿名函数的执行环境中查找zzz,但因为它不在那里,所以它查找匿名函数的父环境(而不是在调用堆栈的上方),并且由于匿名函数是在apply_subset中定义的,父环境是apply_subset的执行环境,在那里找到zzz.

(4) there is any way to make the call to lapply work without using an anonymous function

要做到这一点,将其推广到其他情况,方法是通过使用显式的envir=参数传递环境,如下所示:

subset_base <- function(data, rows, envir = parent.frame()) {   ##
  rows <- substitute(rows)
  rows_val <- eval(rows, data, envir)  ##
  data[rows_val, , drop = FALSE]
}

apply_subset <- function(){
  zzz <- 2
  dfs <- list(data.frame(x = 1:3), data.frame(x = 4:6))
  lapply(dfs, FUN = subset_base, x == zzz, envir = environment()) ##
}

apply_subset()

施舍

[[1]]
  x
2 2

[[2]]
[1] x
<0 rows> (or 0-length row.names)

R相关问答推荐

R形式的一维数字线/箱形图样式图表

terra nearest()仅为所有`to_id`列返回NA

从R导出全局环境中的所有sf(numrames)对象

二维样条,严格以一个参数递增

如何根据嵌套元素的名称高效而优雅地确定它属于哪个列表?

根据列A中的差异变异列,其中行由列B中的相对值标识

R Select()可以测试不存在的子集列

使用rvest从多个页面抓取时避免404错误

将Posict转换为数字时的负时间(以秒为单位)

如何基于两个条件从一列中提取行

当我们有多个反斜杠和/特殊字符时使用Gsubing

将多个列值转换为二进制

将标识符赋给事件序列,避免错误观察

随机森林的带Shap值的蜂群图

如何在ggplot2中创建多个y轴(每个变量一个)

我将工作代码重构为一个函数--现在我想不出如何传递轴列参数

以任意顺序提取具有多个可能匹配项的组匹配项

如何根据其他列中的两个条件来计算数据帧中的行之间的差异?

在使用SliderInput In Shiny(R)设置输入数据的子集时,保留一些情节痕迹

如何在矩阵图中按标准对数据进行分组以绘制矩阵