之间有什么区别。和.data?

Bra*_*ell 10 r dplyr tidyeval

我正在尝试更深入地理解使用点(“.”)dplyr和使用.data代词dplyr。我写的激发这篇文章的代码看起来像这样:

cat_table <- tibble(
  variable = vector("character"), 
  category = vector("numeric"), 
  n        = vector("numeric")
) 

for(i in c("cyl", "vs", "am")) {
  cat_stats <- mtcars %>% 
    count(.data[[i]]) %>% 
    mutate(variable = names(.)[1]) %>%
    rename(category = 1)
  
  cat_table <- bind_rows(cat_table, cat_stats)
}
Run Code Online (Sandbox Code Playgroud)
# A tibble: 7 x 3
  variable category     n
  <chr>       <dbl> <dbl>
1 cyl             4    11
2 cyl             6     7
3 cyl             8    14
4 vs              0    18
5 vs              1    14
6 am              0    19
7 am              1    13
Run Code Online (Sandbox Code Playgroud)

代码做了我想要它做的事情,并不是这个问题的重点。我只是提供它的上下文。

我试图更深入地了解为什么它会做我想要它做的事情。更具体地说,为什么我不能使用..data互换。我读过与dplyr编程的文章,但我想在我的心中,都..data仅仅意味着“我们的结果高达管道这一点。” 但是,似乎我过于简化了我对它们如何工作的心理模型,因为当我.datanames()下面使用inside时出现错误:

mtcars %>% 
  count(.data[["cyl"]]) %>% 
  mutate(variable = names(.data)[1])
Run Code Online (Sandbox Code Playgroud)
Error: Problem with `mutate()` input `variable`.
x Can't take the `names()` of the `.data` pronoun
? Input `variable` is `names(.data)[1]`.
Run `rlang::last_error()` to see where the error occurred.
Run Code Online (Sandbox Code Playgroud)

当我使用.inside时,我得到了一个意想不到的(对我来说)结果count()

mtcars %>% 
  count(.[["cyl"]]) %>% 
  mutate(variable = names(.)[1])
Run Code Online (Sandbox Code Playgroud)
  .[["cyl"]]  n   variable
1          4 11 .[["cyl"]]
2          6  7 .[["cyl"]]
3          8 14 .[["cyl"]]
Run Code Online (Sandbox Code Playgroud)

我怀疑它与“请注意,.data 不是数据框;它是一个特殊的结构,一个代词,它允许您直接访问当前变量,使用 .data$x 或间接使用 .data[ [var]]。不要指望其他函数可以使用它,”来自Programming with dplyr文章。这告诉我什么.data 不是——一个数据框——但是,我仍然不确定什么.data 以及它与..

我试着像这样弄清楚:

mtcars %>% 
  count(.data[["cyl"]]) %>% 
  mutate(variable = list(.data))
Run Code Online (Sandbox Code Playgroud)

但是,结果<S3: rlang_data_pronoun>对我来说没有任何帮助我理解的意义。如果有人对此有更好的了解,我将不胜感激。谢谢!

r2e*_*ans 10

在前面,我认为它.data的意图有点令人困惑,直到人们还考虑它的兄弟代词.env.

.magrittr::%>%设置和使用的东西;因为dplyr重新导出它,它就在那里。每当您引用它时,它都是一个真实的对象,因此names(.)nrow(.)等都按预期工作。它确实反映了管道中到目前为止的数据。

.data另一方面,rlang为了消除符号解析的歧义,在其中定义了 。与 一起.env,它使您可以非常清楚地了解要在何处解析特定符号(当预计会出现歧义时)。从?.data,我认为这是一个清晰的对比:

disp <- 10
mtcars %>% mutate(disp = .data$disp * .env$disp)
mtcars %>% mutate(disp = disp * disp)
Run Code Online (Sandbox Code Playgroud)

然而,正如帮助页面中所述,.data(and .env) 只是一个“代词”(我们有动词,所以现在我们也有代词),所以它只是一个指向应该解析符号的整洁内部结构的指针。这只是某种暗示。

所以你的说法

..data仅仅意味着“我们的结果高达管道这一点。”

不正确:.表示到目前为止的数据,.data只是对内部的声明性提示。


考虑另一种思考方式.data:假设我们有两个函数可以完全消除引用符号的环境的歧义:

  • get_internally, 该符号必须始终引用一个列名,如果该列不存在,它将不会接触到封闭环境;和
  • get_externally,此符号必须始终引用封闭环境中的变量/对象,它永远不会匹配列。

在那种情况下,翻译上面的例子,人们可能会使用

disp <- 10
mtcars %>%
  mutate(disp = get_internally(disp) * get_externally(disp))
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它get_internally不是框架似乎更明显,因此您不能调用names(get_internally)并期望它做一些有意义的事情(除了NULL)。就像names(mutate).

所以不要把它.data当作一个对象,把它当作一种消除符号环境歧义的机制。我认为$它使用的既简洁/易于使用又绝对具有误导性:它不是list-like 或environment-like 对象,即使它被如此对待。

顺便说一句:可以编写任何 S3 方法$,使任何分类对象看起来像一个框架/环境:

`$.quux` <- function(x, nm) paste0("hello, ", nm, "!")
obj <- structure(0, class = "quux")
obj$r2evans
# [1] "hello, r2evans!"
names(obj)
# NULL
Run Code Online (Sandbox Code Playgroud)

(访问器的存在$并不总是意味着对象是框架/环境。)