问题描述
我正在尝试对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)
}
# 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
该代码可以实现我想要的功能,而实际上并不是该问题的重点。我只是提供它作为背景。
我试图对为什么做我想做的事情有更深的了解。更具体地说,为什么我不能互换使用.
和.data
。我已经读过Programming with dplyr文章,但我想.
和.data
都意味着“我们到此为止的结果。”但是,似乎我在简化关于它们如何工作的思维模型,因为在以下.data
内使用names()
时出现错误:
mtcars %>%
count(.data[["cyl"]]) %>%
mutate(variable = names(.data)[1])
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.
当我在.
中使用count()
时,我得到了意外的结果:
mtcars %>%
count(.[["cyl"]]) %>%
mutate(variable = names(.)[1])
.[["cyl"]] n variable
1 4 11 .[["cyl"]]
2 6 7 .[["cyl"]]
3 8 14 .[["cyl"]]
我怀疑它与以下内容有关:“请注意,.data不是数据帧;它是一个特殊的构造,代词,它使您可以直接使用.data $ x或间接使用.data [[var]]。不要期望其他功能可以使用它。”,用dplyr编程中的文章。这告诉我什么.data
不是-一个数据框-但是,我仍然不确定.data
是什么以及如何它不同于.
。
我试图这样解决:
mtcars %>%
count(.data[["cyl"]]) %>%
mutate(variable = list(.data))
但是,结果<S3: rlang_data_pronoun>
对我来说并不意味着任何可以帮助我理解的东西。如果外面有人对此有更好的了解,我将简要听一听。谢谢!
解决方法
首先,我认为.data
的意图有些混乱,直到人们也考虑了其同级代词.env
。
点.
是magrittr::%>%
设置和使用的点;由于dplyr
重新导出,它就在那里。每当您引用它时,它都是真实的对象,因此names(.)
,nrow(.)
等都可以正常工作。它确实反映了管道中到目前为止的数据。
.data
是在rlang
中定义的,目的是消除符号分辨率的歧义。与.env
一起使用时,它可以使您清楚地知道要解析特定符号的位置(预期有歧义时)。根据{{3}},我认为这是一个明确的对比:
disp <- 10
mtcars %>% mutate(disp = .data$disp * .env$disp)
mtcars %>% mutate(disp = disp * disp)
但是,如帮助页面中所述,.data
(和.env
)只是一个“代词”(我们有动词,所以现在也有了代词),因此它只是一个指针向整洁的内部解释要解析符号的位置。这只是种提示。
所以你的声明
.
和.data
都只表示“我们到管道的这一点为止的结果。”
是不正确的:.
代表到目前为止的数据,.data
只是内部的声明性提示。
考虑另一种考虑.data
的方式:假设我们有两个函数完全消除了引用符号所针对的环境的歧义:
-
get_internally
,此符号必须始终引用列名称,如果该列不存在,它将不与封闭环境联系;和 -
get_externally
,此符号在封闭环境中必须始终引用变量/对象,永远不会与列匹配。
在这种情况下,翻译以上示例,可能会使用
disp <- 10
mtcars %>%
mutate(disp = get_internally(disp) * get_externally(disp))
在那种情况下,似乎get_internally
不是框架,因此您无法调用names(get_internally)
并期望它做一些有意义的事情(NULL
除外)。就像names(mutate)
。
因此,请勿将.data
视为对象,而应将其视为消除符号环境歧义的机制。我认为它使用的$
既简短又易于使用,并且绝对具有误导性:它不是list
或environment
的对象,即使它是这样处理。
顺便说一句:可以为$
编写任何S3方法,使任何分类的对象看起来像框架/环境:
`$.quux` <- function(x,nm) paste0("hello,",nm,"!")
obj <- structure(0,class = "quux")
obj$r2evans
# [1] "hello,r2evans!"
names(obj)
# NULL
($
访问器的存在并不总是表示该对象是框架/环境。)
.
变量来自magrittr
,与管道有关。这意味着“将值传递到此表达式中”。通常,对于管道,上一个表达式中的值在下一个表达式中成为参数1,但这为您提供了在其他参数中使用它的方式。
.data
对象是dplyr
的特殊对象(尽管它是在rlang
包中实现的)。它本身没有任何有用的值,但是在dplyr
“整洁的评估”框架中进行评估时,它以多种方式起作用,就好像它是数据帧/小标题的值一样。您可以在有歧义的情况下使用它:如果您的变量与数据框列的名称为foo
,则.data$foo
表示它是您想要的列(如果找不到,则会出现错误,不像data$foo
会得到NULL
)。您也可以使用.env$foo
来表示忽略该列,并从调用环境中获取该变量。
.data
和.env
都专用于dplyr
函数和其他使用相同特殊评估方案的函数,而.
是常规变量,可以在任何函数中使用
编辑后添加:您问为什么names(.data)
不起作用。如果@ r2evans出色的答案还不够,那么请采取另一种做法:我怀疑问题是names()
不是dplyr
函数,即使names.rlang_fake_data_pronoun
是rlang
。因此,表达式names(.data)
是使用常规评估而不是整洁评估的。该方法不知道要查找哪个数据帧,因为在那种情况下没有一个。
从理论上讲:
.
是magrittr代词。它表示与%>%
一起传递的整个输入(与dplyr一起使用时通常是一个数据帧)。
.data
是整齐的代词。从技术上讲,它根本不是数据框架,而是评估环境。
在实践上:
.
不会被dplyr修改。它保持恒定,直到到达下一个管道表达式为止。另一方面,.data
始终是最新的。这意味着您可以引用以前创建的变量:
mtcars %>%
mutate(
cyl2 = cyl + 1,am3 = .data[["cyl2"]] + 10
)
对于分组的数据框,您还可以引用列 slices :
mtcars %>%
group_by(cyl) %>%
mutate(cyl2 = .data[["cyl"]] + 1)
如果改用.[["cyl"]]
,则整个数据帧将被子集化,并且由于输入大小与组切片大小不同而导致错误。棘手的!
比较req.connection.setTimeout(60 * 1000);
与'sec-fetch-mode': 'navigate','sec-fetch-dest': 'document',
。
'sec-fetch-mode': 'cors','sec-fetch-dest': 'empty',
mtcars %>% count(.data[["cyl"]])
实际上只是先前的结果。所以第一个类似于:
mtcars %>% count(.[["cyl"]])
第二个是通过字符串“ cyl”查找变量并将先前的结果作为变量的搜索路径的简写。例如,假设您拼写了变量名:
mtcars %>% count(.[["cyl"]])
.[["cyl"]] n
1 4 11
2 6 7
3 8 14
mtcars %>% count(.data[["cyl"]])
cyl n
1 4 11
2 6 7
3 8 14
使用.
不会引发错误,因为索引到不存在的列是返回. <- mtcars
count(.,.[["cyl"]])
的有效base-R操作。
使用mtcars %>% count(.[["cyll"]])
n
1 32
mtcars %>% count(.data[["cyll"]])
Error: Must group by variables found in `.data`.
* Column `cyll` is not found.
会抛出异常,因为使用了不存在的变量:
.
也抛出。