之间有什么区别。和.data?
What is the difference between . and .data?
我正在尝试加深对 dplyr
中使用点号 (.) 和 dplyr
中使用 .data
代词的理解。我正在编写的激发此 post 的代码看起来像这样:
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
都只是表示“到目前为止我们的结果在管道中”。但是,似乎我过于简化了我对它们如何工作的心智模型,因为当我在下面的 names()
中使用 .data
时出现错误:
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]]。不要指望其他函数可以使用它,”来自 Programming with dplyr 一文。这告诉我什么 .data
不是 -- 数据框 -- 但是,我仍然不确定 .data
是什么 以及它与 .
.
的区别
我试过这样计算:
mtcars %>%
count(.data[["cyl"]]) %>%
mutate(variable = list(.data))
但是,结果 <S3: rlang_data_pronoun>
对我来说没有任何意义可以帮助我理解。如果有人对此有更好的了解,我将不胜感激。谢谢!
首先,我认为 .data
的意图有点令人困惑,直到人们还考虑了它的兄弟代词 .env
。
点 .
是 magrittr::%>%
设置和使用的东西;因为 dplyr
re-exports 它就在那里。每当你引用它时,它都是一个真实的对象,所以 names(.)
、nrow(.)
等都按预期工作。它确实反映了管道中到目前为止的数据。
另一方面,.data
是在 rlang
中定义的,目的是消除符号解析的歧义。与 .env
一起,它使您可以非常清楚地知道要在何处解析特定符号(当预期存在歧义时)。来自?.data
,我认为这是一个清晰的对比:
disp <- 10
mtcars %>% mutate(disp = .data$disp * .env$disp)
mtcars %>% mutate(disp = disp * disp)
然而,如帮助页面所述,.data
(和.env
)只是一个“代词”(我们有动词,所以现在我们也有代词),所以它只是一个指针,用于解释应该解析符号的整洁内部结构。这只是某种暗示。
所以你的说法
both .
and .data
just mean "our result up to this point in the pipeline."
不正确:.
表示到目前为止的数据,.data
只是对内部的声明性提示。
考虑另一种思考 .data
的方式:假设我们有两个函数可以完全消除引用符号所针对的环境的歧义:
get_internally
,这个符号必须总是引用一个列名,如果列不存在,它不会接触到封闭环境;和
get_externally
,此符号必须始终引用封闭环境中的 variable/object,它永远不会匹配列。
那样的话,翻译上面的例子,可以用
disp <- 10
mtcars %>%
mutate(disp = get_internally(disp) * get_externally(disp))
在那种情况下,get_internally
不是框架似乎更明显,因此您不能调用 names(get_internally)
并期望它做一些有意义的事情(除了 NULL
).就像 names(mutate)
.
所以不要将 .data
视为对象,而应将其视为消除符号环境歧义的机制。我认为它使用的 $
既是 terse/easy-to-use 又是 absolutely-misleading:它不是 list
-like 或 environment
-like 对象,即使它正在如此对待。
顺便说一句:可以为 $
编写任何 S3 方法,使任何 classed-object 看起来像 frame/environment:
`$.quux` <- function(x, nm) paste0("hello, ", nm, "!")
obj <- structure(0, class = "quux")
obj$r2evans
# [1] "hello, r2evans!"
names(obj)
# NULL
($
访问器的存在并不总是意味着该对象是 frame/env。)
比较 mtcars %>% count(.data[["cyl"]])
与 mtcars %>% count(.[["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"]])
第二个是shorthand,用于通过字符串“cyl”查找变量,并将前一个结果作为变量的搜索路径。例如,假设您拼错了变量名称:
mtcars %>% count(.[["cyll"]])
n
1 32
mtcars %>% count(.data[["cyll"]])
Error: Must group by variables found in `.data`.
* Column `cyll` is not found.
使用 .
不会引发错误,因为索引到 non-existing 列是 returns NULL
.[=20 的有效 base-R 操作=]
使用 .data
会抛出异常,因为使用 non-existent 变量:
mtcars %>% count(cyll)
也抛出。
.
变量来自magrittr
,与管道有关。它的意思是“通过管道输送到这个表达式中的值”。通常对于管道,前一个表达式的值成为下一个表达式中的参数 1,但这为您提供了一种在其他参数中使用它的方法。
.data
对象对于 dplyr
是特殊的(虽然它是在 rlang
包中实现的)。它本身没有任何有用的值,但在 dplyr
“整洁评估”框架中进行评估时,它在许多方面的作用就好像它是 dataframe/tibble 的值一样。当有歧义时使用它:如果你有一个与数据框列同名 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
)
在分组数据框的情况下,您还可以参考列切片:
mtcars %>%
group_by(cyl) %>%
mutate(cyl2 = .data[["cyl"]] + 1)
如果您改用 .[["cyl"]]
,整个数据框将被子集化,您将收到一个错误,因为输入大小与组切片大小不同。棘手!
我正在尝试加深对 dplyr
中使用点号 (.) 和 dplyr
中使用 .data
代词的理解。我正在编写的激发此 post 的代码看起来像这样:
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
都只是表示“到目前为止我们的结果在管道中”。但是,似乎我过于简化了我对它们如何工作的心智模型,因为当我在下面的 names()
中使用 .data
时出现错误:
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]]。不要指望其他函数可以使用它,”来自 Programming with dplyr 一文。这告诉我什么 .data
不是 -- 数据框 -- 但是,我仍然不确定 .data
是什么 以及它与 .
.
我试过这样计算:
mtcars %>%
count(.data[["cyl"]]) %>%
mutate(variable = list(.data))
但是,结果 <S3: rlang_data_pronoun>
对我来说没有任何意义可以帮助我理解。如果有人对此有更好的了解,我将不胜感激。谢谢!
首先,我认为 .data
的意图有点令人困惑,直到人们还考虑了它的兄弟代词 .env
。
点 .
是 magrittr::%>%
设置和使用的东西;因为 dplyr
re-exports 它就在那里。每当你引用它时,它都是一个真实的对象,所以 names(.)
、nrow(.)
等都按预期工作。它确实反映了管道中到目前为止的数据。
.data
是在 rlang
中定义的,目的是消除符号解析的歧义。与 .env
一起,它使您可以非常清楚地知道要在何处解析特定符号(当预期存在歧义时)。来自?.data
,我认为这是一个清晰的对比:
disp <- 10
mtcars %>% mutate(disp = .data$disp * .env$disp)
mtcars %>% mutate(disp = disp * disp)
然而,如帮助页面所述,.data
(和.env
)只是一个“代词”(我们有动词,所以现在我们也有代词),所以它只是一个指针,用于解释应该解析符号的整洁内部结构。这只是某种暗示。
所以你的说法
both
.
and.data
just mean "our result up to this point in the pipeline."
不正确:.
表示到目前为止的数据,.data
只是对内部的声明性提示。
考虑另一种思考 .data
的方式:假设我们有两个函数可以完全消除引用符号所针对的环境的歧义:
get_internally
,这个符号必须总是引用一个列名,如果列不存在,它不会接触到封闭环境;和get_externally
,此符号必须始终引用封闭环境中的 variable/object,它永远不会匹配列。
那样的话,翻译上面的例子,可以用
disp <- 10
mtcars %>%
mutate(disp = get_internally(disp) * get_externally(disp))
在那种情况下,get_internally
不是框架似乎更明显,因此您不能调用 names(get_internally)
并期望它做一些有意义的事情(除了 NULL
).就像 names(mutate)
.
所以不要将 .data
视为对象,而应将其视为消除符号环境歧义的机制。我认为它使用的 $
既是 terse/easy-to-use 又是 absolutely-misleading:它不是 list
-like 或 environment
-like 对象,即使它正在如此对待。
顺便说一句:可以为 $
编写任何 S3 方法,使任何 classed-object 看起来像 frame/environment:
`$.quux` <- function(x, nm) paste0("hello, ", nm, "!")
obj <- structure(0, class = "quux")
obj$r2evans
# [1] "hello, r2evans!"
names(obj)
# NULL
($
访问器的存在并不总是意味着该对象是 frame/env。)
比较 mtcars %>% count(.data[["cyl"]])
与 mtcars %>% count(.[["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"]])
第二个是shorthand,用于通过字符串“cyl”查找变量,并将前一个结果作为变量的搜索路径。例如,假设您拼错了变量名称:
mtcars %>% count(.[["cyll"]])
n
1 32
mtcars %>% count(.data[["cyll"]])
Error: Must group by variables found in `.data`.
* Column `cyll` is not found.
使用 .
不会引发错误,因为索引到 non-existing 列是 returns NULL
.[=20 的有效 base-R 操作=]
使用 .data
会抛出异常,因为使用 non-existent 变量:
mtcars %>% count(cyll)
也抛出。
.
变量来自magrittr
,与管道有关。它的意思是“通过管道输送到这个表达式中的值”。通常对于管道,前一个表达式的值成为下一个表达式中的参数 1,但这为您提供了一种在其他参数中使用它的方法。
.data
对象对于 dplyr
是特殊的(虽然它是在 rlang
包中实现的)。它本身没有任何有用的值,但在 dplyr
“整洁评估”框架中进行评估时,它在许多方面的作用就好像它是 dataframe/tibble 的值一样。当有歧义时使用它:如果你有一个与数据框列同名 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 代词。它表示通过 %>%
.
.data
是整洁的评估代词。从技术上讲它根本不是一个数据框架,它是一个评估环境。
实用层面:
.
永远不会被dplyr修改。它保持不变,直到到达下一个管道表达式。另一方面,.data
始终是最新的。这意味着您可以引用以前创建的变量:
mtcars %>%
mutate(
cyl2 = cyl + 1,
am3 = .data[["cyl2"]] + 10
)
在分组数据框的情况下,您还可以参考列切片:
mtcars %>%
group_by(cyl) %>%
mutate(cyl2 = .data[["cyl"]] + 1)
如果您改用 .[["cyl"]]
,整个数据框将被子集化,您将收到一个错误,因为输入大小与组切片大小不同。棘手!