为何`.data`代词使用环境中的变量而非数据框中的变量?
关于dplyr::filter中.data代词与变量查找的疑问
先看这段示例代码:
library(dplyr) colname = "bar" d = tibble(foo = 1:5, bar = 2:6, colname = "foo") filter(d, .data[[colname]] == 3)
这里存在两个colname变量:一个是全局环境中的变量,值为"bar";另一个是tibbled中的列,所有行的值都是"foo"。
根据?dplyr::filter的文档说明,filter()的第二个参数是基于数据框变量的逻辑表达式;而?rlang::.data文档明确指出:
.data从数据框中检索数据变量。
按文档描述,filter()应该优先从数据框d中查找变量,也就是用d里的colname值("foo")来索引.data,最终等价于执行filter(d, foo == 3)。
但实际运行代码后得到的结果是:
filter(d, .data[[colname]] == 3) #> # A tibble: 1 × 3 #> foo bar colname #> <int> <int> <chr> #> 1 2 3 foo
显然这里用的是全局环境中colname的值("bar"),筛选出了bar列等于3的行。而预期的结果应该是:
filter(d, foo == 3) #> # A tibble: 1 × 3 #> foo bar colname #> <int> <int> <chr> #> 1 3 4 foo
原因解析
.data代词的作用范围是它直接索引的目标,也就是说.data[[x]]的执行逻辑是:先在当前调用环境(这里是全局环境)中计算x的值,再用这个值作为列名去.data指代的数据框中提取对应列。
如果想要用数据框d中的colname列值来作为索引,需要明确让colname也在.data的上下文里求值,比如修改代码为:
# 方式1:用.data明确引用数据框内的colname列 filter(d, .data[[.data$colname]] == 3) # 方式2:先提取数据框中的colname值再使用 target_col = d$colname[1] filter(d, .data[[target_col]] == 3)
这样就能得到预期的筛选结果。
内容的提问来源于stack exchange,提问作者Karl Ove Hufthammer
相关产品推荐
相关产品推荐

