Yuk*_*mon 12 r dplyr nse tidyverse tidyeval
我使用动态变量(例如ID)作为引用列名的方式,该列名将根据我当时正在处理的基因而改变。然后我使用case_wheninsidemutate创建一个新列,该列的值取决于动态列。
我认为!!(bang-bang) 是我强制对变量内容进行 eval 所需要的;但是,我没有在我的新专栏中得到预期的输出。只有!!as.name给了我期望的输出,我不完全明白为什么。有人可以解释为什么在这种情况下使用 only!!是不合适的,以及发生了!!as.name什么?
这是我制作的一个简单的可重现示例,用于演示我所体验的内容:
library(tidyverse)
ID <- "birth_year"
# Correct output
test <- starwars %>%
mutate(FootballLeague = case_when(
!!as.name(ID) < 10 ~ "U10",
!!as.name(ID) >= 10 & !!as.name(ID) < 50 ~ "U50",
!!as.name(ID) >= 50 & !!as.name(ID) < 100 ~ "U100",
!!as.name(ID) >= 100 ~ "Senior",
TRUE ~ "Others"
))
# Incorrect output
test2 <- starwars %>%
mutate(FootballLeague = case_when(
!!(ID) < 10 ~ "U10",
!!(ID) >= 10 & !!(ID) < 50 ~ "U50",
!!(ID) >= 50 & !!(ID) < 100 ~ "U100",
!!(ID) >= 100 ~ "Senior",
TRUE ~ "Others"
))
# Incorrect output
test3 <- starwars %>%
mutate(FootballLeague = case_when(
as.name(ID) < 10 ~ "U10",
as.name(ID) >= 10 & as.name(ID) < 50 ~ "U50",
as.name(ID) >= 50 & as.name(ID) < 100 ~ "U100",
as.name(ID) >= 100 ~ "Senior",
TRUE ~ "Others"
))
identical(test, test2)
# FALSE
identical(test2, test3)
# TRUE
sessionInfo()
#R version 4.0.2 (2020-06-22)
#Platform: x86_64-centos7-linux-gnu (64-bit)
#Running under: CentOS Linux 7 (Core)
# tidyverse_1.3.0
# dplyr_1.0.2
Run Code Online (Sandbox Code Playgroud)
干杯!
AEF*_*AEF 11
您可以将表达式包装在函数中quo()以查看应用!!运算符后的运算结果。为简单起见,我将使用较短的表达式进行演示:
准备工作:
library(tidyverse)
ID <- "birth_year"
## Test without quasiquotation:
starwars %>%
filter(birth_year < 50)
Run Code Online (Sandbox Code Playgroud)
实验一:
quo(
starwars %>%
filter(ID < 50)
)
## result: starwars %>% filter(ID < 50)
Run Code Online (Sandbox Code Playgroud)
我们了解到:filter()不ID视为变量,而是“原样”。所以我们需要一种机制来告诉filter()它应该将其ID视为变量,并且应该使用它的值。
-->!!运算符可用于告诉filter()它应该将表达式视为变量并替换其值。
实验二:
quo(
starwars %>%
filter(!!ID < 50)
)
## result: starwars %>% filter("birth_year" < 50)
Run Code Online (Sandbox Code Playgroud)
我们了解到:!!操作符确实有效:ID被它的值所取代。但是:的值ID是字符串 "birth_year"。注意结果中的引号。但是您可能知道,tidyverse 函数不将变量名作为字符串,它们需要原始名称,不带引号。与实验 1 比较:filter()“按原样”接受所有内容,因此它查找名为"birth_year"(包括引号!)的列
函数as.name()有什么作用?
这是一个基本的 R 函数,它接受一个字符串(或一个包含字符串的变量)并返回字符串的内容作为变量名。因此,如果您调用as.name(ID)base R,结果是birth_year,这次没有引号 - 就像 tidyverse 所期望的那样。让我们试试看:
实验3:
quo(
starwars %>%
filter(as.name(ID) < 50)
)
## result: starwars %>% filter(as.name(ID) < 50)
Run Code Online (Sandbox Code Playgroud)
我们了解到:这行不通,因为再次filter()将一切“按原样”处理。所以现在它查找名为 的列as.name(ID),这当然不存在。
--> 我们需要把这两件事结合起来才能让它工作:
as.name()的字符串转换为一个变量名。!!告诉filter()它不应该带的东西“原样”,但替换的实际价值。实验四:
quo(
starwars %>%
filter(!!as.name(ID) < 50)
)
## result: starwars %>% filter(birth_year < 50)
Run Code Online (Sandbox Code Playgroud)
现在它起作用了!:)
我filter()在我的实验中使用过,但它mutate()与其他 tidyverse 函数的工作原理完全相同。
| 归档时间: |
|
| 查看次数: |
344 次 |
| 最近记录: |