dplyr的升级版本弃用了函数的下划线版本,例如filter_,而不是tidy evaluation。
新方式的下划线表格的新形式是什么?如何使用R CMD检查来编写避免未定义的符号?
library(dplyr)
df <- data_frame(id = rep(c("a","b"), 3), val = 1:6)
df %>% filter_(~id == "a")
# want to avoid this, because it references column id in a variable-style
df %>% filter( id == "a" )
# option A
df %>% filter( UQ(rlang::sym("id")) == "a" )
# option B
df %>% filter( UQ(as.name("id")) == "a" )
# option C
df %>% filter( .data$id == "a" )
是否有首选或更体贴的形式?选项C是最短的,但在我的一些现实世界较大的数据集和更复杂的dplyr结构上速度较慢:
microbenchmark(
sym = dsPClosest %>%
group_by(!!sym(dateVarName), !!sym("depth")) %>%
summarise(temperature = mean(!!sym("temperature"), na.rm = TRUE)
, moisture = mean(!!sym("moisture"), na.rm = TRUE)) %>%
ungroup()
,data = dsPClosest %>%
group_by(!!sym(dateVarName), .data$depth ) %>%
summarise(temperature = mean(.data$temperature , na.rm = TRUE)
, moisture = mean(.data$moisture , na.rm = TRUE)) %>%
ungroup()
,times=10
)
#Unit: milliseconds
# expr min lq mean median uq max neval
# sym 80.05512 84.97267 122.7513 94.79805 100.9679 392.1375 10
# data 4652.83104 4741.99165 5371.5448 5039.63307 5471.9261 7926.7648 10
还有另一个answer for mutate_使用更复杂的语法。
答案 0 :(得分:2)
根据您的评论,我猜是:
df %>% filter(!!as.name("id") == "a")
rlang
是不必要的,因为您可以使用!!
和as.name
代替UQ
和sym
执行此操作。
但也许更好的选择是范围过滤器,它避免了与quosure相关的问题:
df %>% filter_at(vars("id"), all_vars(. == "a"))
在上面的代码vars()
中确定我们将要应用过滤语句的哪些列(在filter_at
的帮助中,过滤语句称为&#34;谓词&# 34;在这种情况下,vars("id")
表示过滤语句仅应用于id
列。过滤语句可以是all_vars()
或any_vars()
语句,尽管它们是& #39;在这种情况下相同。all_vars(. == "a")
表示vars("id")
中的所有列都必须等于"a"
。是的,它有点令人困惑。
与您的示例类似的数据计时:在这种情况下,我们使用group_by_at
和summarise_at
,它们是这些函数的范围版本:
set.seed(2)
df <- data_frame(group = sample(1:100,1e4*52,replace=TRUE),
id = rep(c(letters,LETTERS), 1e4),
val = sample(1:50,1e4*52,replace=TRUE))
microbenchmark(
quosure=df %>% group_by(!!as.name("group"), !!as.name("id")) %>%
summarise(val = mean(!!as.name("val"))),
data=df %>% group_by(.data$group, .data$id) %>%
summarise(val = mean(.data$val)),
scoped_group_by = df %>% group_by_at(vars("group","id")) %>%
summarise_at("val", mean), times=10)
Unit: milliseconds expr min lq mean median uq max neval cld quosure 59.29157 61.03928 64.39405 62.60126 67.93810 72.47615 10 a data 391.22784 394.65636 419.24201 413.74683 425.11709 498.42660 10 b scoped_group_by 69.57573 71.21068 78.26388 76.67216 82.89914 91.45061 10 a
原始答案
我认为这是一种情况,您可以将过滤器变量作为裸名称输入,然后使用enquo
和!!
(相当于UQ
)来使用过滤器变量。例如:
library(dplyr)
fnc = function(data, filter_var, filter_value) {
filter_var=enquo(filter_var)
data %>% filter(!!filter_var == filter_value)
}
fnc(df, id, "a")
id val 1 a 1 2 a 3 3 a 5
fnc(mtcars, carb, 3)
mpg cyl disp hp drat wt qsec vs am gear carb 1 16.4 8 275.8 180 3.07 4.07 17.4 0 0 3 3 2 17.3 8 275.8 180 3.07 3.73 17.6 0 0 3 3 3 15.2 8 275.8 180 3.07 3.78 18.0 0 0 3 3
答案 1 :(得分:0)
# option D: uses formula instead of string
df %>% filter( UQ(f_rhs(~id)) == "a" )
仍然相当冗长,但避免双引号。
微基准测试与选项B相同(或者更快速地打勾),即as.name解决方案。
答案 2 :(得分:0)
# option F: using the dot .
df %>% filter( .$id == "a" )
# slow in progtw's real-world problem:
microbenchmark(
sym = dsPClosest %>%
group_by(!!sym(dateVarName), !!sym("depth")) %>%
summarise(temperature = mean(!!sym("temperature"), na.rm = TRUE)
, moisture = mean(!!sym("moisture"), na.rm = TRUE)) %>%
ungroup()
,dot = dsPClosest %>%
group_by(!!sym(dateVarName), .$depth ) %>%
summarise(temperature = mean(.$temperature , na.rm = TRUE)
, moisture = mean(.$moisture , na.rm = TRUE)) %>%
ungroup()
,times=10
)
#Unit: milliseconds
# expr min lq mean median uq max neval
# sym 75.37921 78.86365 90.72871 81.22674 90.77943 163.2081 10
# dot 115452.88945 116260.32703 128314.44451 125162.46876 136578.09888 149193.9751 10
与选项c(.data $)类似,但更短。但是,在我的实际应用程序中表现不佳。
此外,我没有找到何时可以使用的文档。