Tidyverse:为什么将 helper 放在 crops 内部时,选择 helper 会通过管道传递到 carrow() 抛出关于外部向量的 note/warning/error?
Tidyverse: Why does selection helper piped to across() throw note/warning/error about external vector when placing helper inside across does not?
将选择助手(matches()
、contains()
、starts_with()
、ends_with()
)通过管道(的值)传递给 across()
函数的行为与将选择助手放在 across()
.
的括号内
- 为什么会这样?
- 这是预期的行为还是错误?
重现
library(dplyr)
# Very simple function: returns input
self = function(x){x}
# Data to manipulate
dtemp = tibble(var = 1:2)
# No note/warning/error when selection helper is inside across()
dtemp %>% mutate(across(matches("var"), self))
# Note/warning/error when selection helper is piped to across()
dtemp %>% mutate(matches("var") %>% across(self))
观察到的行为
最后一行导致 R 打印
Note: Using an external vector in selections is ambiguous.
i Use `all_of(.)` instead of `.` to silence this message.
i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
请注意此消息每个会话只打印一次,因此您必须重新启动 R 才能再次看到它(除非有其他方法可以重置控制此打印的计数器).
倒数第二条命令(matches()
内 across()
)不会导致 R 打印注释。
预期行为
最后两个命令的行为相同。
附加信息
- dplyr 版本:1.0.6
- tidyverse 版本:1.3.1
> sessionInfo()
R version 4.0.3 (2020-10-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19042)
Matrix products: default
locale:
[1] LC_COLLATE=English_United States.1252 LC_CTYPE=English_United States.1252
[3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C
[5] LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] dplyr_1.0.6
loaded via a namespace (and not attached):
[1] fansi_0.5.0 assertthat_0.2.1 utf8_1.2.1 crayon_1.4.1
[5] R6_2.5.0 DBI_1.1.1 lifecycle_1.0.0 magrittr_2.0.1
[9] pillar_1.6.1 cli_2.5.0 rlang_0.4.11 rstudioapi_0.13
[13] vctrs_0.3.8 generics_0.1.0 ellipsis_0.3.2 tools_4.0.3
[17] glue_1.4.2 purrr_0.3.4 compiler_4.0.3 pkgconfig_2.0.3
[21] tidyselect_1.1.1 tibble_3.1.2
关于OP的问题
Is this the expected behavior or a bug?
包的一位作者github issue已经在github issue中提到了它
This type of variable lookup in selection contexts now triggers a message:
matches
returns 一个字符向量。在最近的 dplyr
版本中,引入了 all_of
以消除歧义。假设您有一个包含两列 x
和 y
的 data.frame
此外,假设您有一个变量 x = 'y'
。现在,如果您 select(x)
,您指的是 x
列还是 y
列? all_of(x)
将消除这种歧义。因此,当您将 matches
传递给 across
时,看起来您正在选择一个名为 .
的字符向量。这样做的原因是评估选择助手本身只是 returns 一个向量作为 .cols 的参数。这就是 R 管道和输入的基本原理。您可以使用 rlang::quo
对此进行测试。如果 f <- function(x) rlang::quo(x)
,则 运行 f(1)
不同于 运行 1 %>% f
。第一个 returns 引用 1 第二个 returns 引用 .
。因此,如果我们评估 across(<selection-helper>)
这与评估 f(1)
相同,而 <selection-helper> %>% across()
与 1 %>% f()
相同。因为后者看起来像一个变量 .
,它有一个包含其值的专用环境(因此它看起来像一个名为 .
.
的向量
为了清楚起见,让我们看一下输出:
library(magrittr)
f <- function(x) rlang::enquo(x)
f(1)
#> <quosure>
#> expr: ^1
#> env: empty
1 %>%
f()
#> <quosure>
#> expr: ^.
#> env: 00000000166DD798
`%>%`(1,f)
#> <quosure>
#> expr: ^.
#> env: 00000000165176F0
由 reprex package (v2.0.0) 于 2021-06-24 创建
第一个输出捕获并引用 1
(它没有环境,它不是 object/symbol),在使用管道命令时,我们将 lhs
的值存储在具有 symbol/name .
。值 1
现在包含在该环境中。这就是管道工作原理的本质。将 lhs
值存储在名为 .
的环境中,然后将其作为第一个参数放入 rhs
中(除非 .
放在其他地方)并对其求值。
因此,它会抛出警告,因为看起来您输入的是符号而不是值。如果你保持里面的<selection-help>
跨过来,它就不是一个symbol/object它是一个字符向量,字符向量没有歧义(因为它不是符号)。原理同f(1)
。我希望这能说明一些问题。需要注意的是,一旦我们评估输入,它就不再是 .
而是它的真实值。
您可以通过在引用 x
之前添加 print(x)
来查看这一点。
您可以在高级 R 编程 https://adv-r.hadley.nz/ 中阅读更多相关信息,主要是第 7 章,以了解元编程部分中 R 引用、承诺和评估中的环境。
将选择助手(matches()
、contains()
、starts_with()
、ends_with()
)通过管道(的值)传递给 across()
函数的行为与将选择助手放在 across()
.
- 为什么会这样?
- 这是预期的行为还是错误?
重现
library(dplyr)
# Very simple function: returns input
self = function(x){x}
# Data to manipulate
dtemp = tibble(var = 1:2)
# No note/warning/error when selection helper is inside across()
dtemp %>% mutate(across(matches("var"), self))
# Note/warning/error when selection helper is piped to across()
dtemp %>% mutate(matches("var") %>% across(self))
观察到的行为
最后一行导致 R 打印
Note: Using an external vector in selections is ambiguous.
i Use `all_of(.)` instead of `.` to silence this message.
i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
请注意此消息每个会话只打印一次,因此您必须重新启动 R 才能再次看到它(除非有其他方法可以重置控制此打印的计数器).
倒数第二条命令(matches()
内 across()
)不会导致 R 打印注释。
预期行为
最后两个命令的行为相同。
附加信息
- dplyr 版本:1.0.6
- tidyverse 版本:1.3.1
> sessionInfo()
R version 4.0.3 (2020-10-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19042)
Matrix products: default
locale:
[1] LC_COLLATE=English_United States.1252 LC_CTYPE=English_United States.1252
[3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C
[5] LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] dplyr_1.0.6
loaded via a namespace (and not attached):
[1] fansi_0.5.0 assertthat_0.2.1 utf8_1.2.1 crayon_1.4.1
[5] R6_2.5.0 DBI_1.1.1 lifecycle_1.0.0 magrittr_2.0.1
[9] pillar_1.6.1 cli_2.5.0 rlang_0.4.11 rstudioapi_0.13
[13] vctrs_0.3.8 generics_0.1.0 ellipsis_0.3.2 tools_4.0.3
[17] glue_1.4.2 purrr_0.3.4 compiler_4.0.3 pkgconfig_2.0.3
[21] tidyselect_1.1.1 tibble_3.1.2
关于OP的问题
Is this the expected behavior or a bug?
包的一位作者github issue已经在github issue中提到了它
This type of variable lookup in selection contexts now triggers a message:
matches
returns 一个字符向量。在最近的 dplyr
版本中,引入了 all_of
以消除歧义。假设您有一个包含两列 x
和 y
的 data.frame
此外,假设您有一个变量 x = 'y'
。现在,如果您 select(x)
,您指的是 x
列还是 y
列? all_of(x)
将消除这种歧义。因此,当您将 matches
传递给 across
时,看起来您正在选择一个名为 .
的字符向量。这样做的原因是评估选择助手本身只是 returns 一个向量作为 .cols 的参数。这就是 R 管道和输入的基本原理。您可以使用 rlang::quo
对此进行测试。如果 f <- function(x) rlang::quo(x)
,则 运行 f(1)
不同于 运行 1 %>% f
。第一个 returns 引用 1 第二个 returns 引用 .
。因此,如果我们评估 across(<selection-helper>)
这与评估 f(1)
相同,而 <selection-helper> %>% across()
与 1 %>% f()
相同。因为后者看起来像一个变量 .
,它有一个包含其值的专用环境(因此它看起来像一个名为 .
.
为了清楚起见,让我们看一下输出:
library(magrittr)
f <- function(x) rlang::enquo(x)
f(1)
#> <quosure>
#> expr: ^1
#> env: empty
1 %>%
f()
#> <quosure>
#> expr: ^.
#> env: 00000000166DD798
`%>%`(1,f)
#> <quosure>
#> expr: ^.
#> env: 00000000165176F0
由 reprex package (v2.0.0) 于 2021-06-24 创建
第一个输出捕获并引用 1
(它没有环境,它不是 object/symbol),在使用管道命令时,我们将 lhs
的值存储在具有 symbol/name .
。值 1
现在包含在该环境中。这就是管道工作原理的本质。将 lhs
值存储在名为 .
的环境中,然后将其作为第一个参数放入 rhs
中(除非 .
放在其他地方)并对其求值。
因此,它会抛出警告,因为看起来您输入的是符号而不是值。如果你保持里面的<selection-help>
跨过来,它就不是一个symbol/object它是一个字符向量,字符向量没有歧义(因为它不是符号)。原理同f(1)
。我希望这能说明一些问题。需要注意的是,一旦我们评估输入,它就不再是 .
而是它的真实值。
您可以通过在引用 x
之前添加 print(x)
来查看这一点。
您可以在高级 R 编程 https://adv-r.hadley.nz/ 中阅读更多相关信息,主要是第 7 章,以了解元编程部分中 R 引用、承诺和评估中的环境。