dplyr 0.7的发布包括使用dplyr进行major overhaul编程。我仔细阅读了本文档,并试图了解它对我使用dplyr的影响。
这是我在使用dplyr构建报告和聚合函数时使用的常用习语:
my_report <- function(data, grouping_vars) {
data %>%
group_by_(.dots=grouping_vars) %>%
summarize(x_mean=mean(x), x_median=median(x), ...)
}
此处,grouping_vars
是字符串向量。
我喜欢这个习惯用法,因为我可以传递来自其他地方的字符串向量,例如文件或Shiny应用程序的反应性UI,但对于交互式工作也不是太糟糕。
然而,在新的programming with dplyr vignette中,我没有看到使用新的dplyr如何完成这样的事情的例子。我只看到如何传递字符串不再是正确方法的示例,我必须使用quosures。
我很高兴采用quosures,但是我究竟如何从字符串到dplyr预期的这些情况?期望整个R生态系统向dplyr提供数据似乎是不可行的 - 很多时候我们会得到字符串并且它们必须被转换。
这是一个示例,显示您现在应该做什么,以及我的旧习惯用法不起作用:
library(dplyr)
grouping_vars <- quo(am)
mtcars %>%
group_by(!!grouping_vars) %>%
summarise(mean_cyl=mean(cyl))
#> # A tibble: 2 × 2
#> am mean_cyl
#> <dbl> <dbl>
#> 1 0 6.947368
#> 2 1 5.076923
grouping_vars <- "am"
mtcars %>%
group_by(!!grouping_vars) %>%
summarise(mean_cyl=mean(cyl))
#> # A tibble: 1 × 2
#> `"am"` mean_cyl
#> <chr> <dbl>
#> 1 am 6.1875
答案 0 :(得分:11)
dplyr
将有一个专门的group_by函数group_by_at
来处理多个分组变量。使用_at
系列的新成员会更容易:
# using the pre-release 0.6.0
cols <- c("am","gear")
mtcars %>%
group_by_at(.vars = cols) %>%
summarise(mean_cyl=mean(cyl))
# Source: local data frame [4 x 3]
# Groups: am [?]
#
# am gear mean_cyl
# <dbl> <dbl> <dbl>
# 1 0 3 7.466667
# 2 0 4 5.000000
# 3 1 4 4.500000
# 4 1 5 6.000000
.vars
参数接受由vars
生成的字符/数字向量或列名:
.vars
由vars()生成的列列表,或者是字符向量 列名称或列位置的数字向量。
答案 1 :(得分:10)
这是我为自己写的快速而肮脏的参考资料。
rlang::sym
使用rlang::syms
和summ_var <- "value"
group_vars <- c("cat", "cat2")
summ_sym <- rlang::sym(summ_var) # capture a single symbol
group_syms <- rlang::syms(group_vars) # creates list of symbols
dat %>%
group_by(!!!group_syms) %>% # splice list of symbols into a function call
summarize(summ = sum(!!summ_sym)) # slice single symbol into call
将字符串转换为符号对象。
!!
如果您在!!!
功能之外使用dplyr
或rlang::sym
,则会收到错误。
rlang::syms
和summarize_by <- function(df, summ_var, group_vars) {
summ_sym <- rlang::sym(summ_var)
group_syms <- rlang::syms(group_vars)
df %>%
group_by(!!!group_syms) %>%
summarize(summ = sum(!!summ_sym))
}
的用法在函数内部是相同的。
summarize_by
然后我们可以使用字符串参数调用summarize_by(dat, "value", c("cat", "cat2"))
。
summ_quo <- quo(value) # capture a single variable for NSE
group_quos <- quos(cat, cat2) # capture list of variables for NSE
dat %>%
group_by(!!!group_quos) %>% # use !!! with both quos and rlang::syms
summarize(summ = sum(!!summ_quo)) # use !! both quo and rlang::sym
enquo
quo
而不是quos
。 summarize_by <- function(df, summ_var, ...) {
summ_quo <- enquo(summ_var) # can only capture a single value!
group_quos <- quos(...) # captures multiple values, also inside functions!?
df %>%
group_by(!!!group_quos) %>%
summarize(summ = sum(!!summ_quo))
}
虽然没问题!?summarize_by(dat, value, cat, cat2)
然后我们的函数调用是
{{1}}
答案 2 :(得分:6)
如果您想按多列分组,可以使用quos
grouping_vars <- quos(am, gear)
mtcars %>%
group_by(!!!grouping_vars) %>%
summarise(mean_cyl=mean(cyl))
# am gear mean_cyl
# <dbl> <dbl> <dbl>
# 1 0 3 7.466667
# 2 0 4 5.000000
# 3 1 4 4.500000
# 4 1 5 6.000000
现在,似乎没有一种方法可以将字符串变成混乱。这是一种有效的方法
cols <- c("am","gear")
grouping_vars <- rlang::parse_quosures(paste(cols, collapse=";"))
mtcars %>%
group_by(!!!grouping_vars) %>%
summarise(mean_cyl=mean(cyl))
# am gear mean_cyl
# <dbl> <dbl> <dbl>
# 1 0 3 7.466667
# 2 0 4 5.000000
# 3 1 4 4.500000
# 4 1 5 6.000000