使用purrr和dplyr:是rlang :: sym最好的方式

时间:2018-01-06 20:28:49

标签: r dplyr purrr rlang

我想编写使用dplyr动词的函数,这意味着我必须涉及rlang的阴暗水域。

为了提供一个具体的例子,假设我想使用purrr::map_df()迭代dplyr::group_by()中的变量。 programming with dplyr小插图通过编写my_summarise()函数来完成;方法是在分组变量上使用rlang::enquo(),然后用!!取消引用。 这种方法可以创建一个类似于dplyr的新函数,该函数采用不带引号的变量名称(在插图中my_summarise(df, g1))。

相反,我想purrr提供变量名称作为字符串。 rlang::sym()是正确的方法吗?它似乎不是,因为在{dplyr编程小插图中没有提到sym()而在rlang tidy evaluation article中几乎没有提到。{1}}。还有更好的方法吗?

library(tidyverse)
my_summarise <- function(df, group_var) {
  group_var <- rlang::sym(group_var)

  df %>%
    group_by(!!group_var) %>%
    summarise(mpg = mean(mpg))
}

# This works. Is that a good thing?
purrr::map_df(c("cyl", "am"), my_summarise, df = mtcars)

# A tibble: 5 x 3
    cyl   mpg    am
  <dbl> <dbl> <dbl>
1  4.00  26.7 NA   
2  6.00  19.7 NA   
3  8.00  15.1 NA   
4 NA     17.1  0   
5 NA     24.4  1.00

作为后续行动,为什么在某些情况下简单地取消引用(先不应用enquosym)?在下面的示例中,为什么select()按预期工作但group_by()没有?

x <- "cyl"
select(mtcars, !!x)
group_by(mtcars, !!x)

更新:答案不是关于取消引用。 select group_by更灵活,可以处理字符串,<div class="col-md-6" ng-repeat="round in displaymatch.allrounds> <h3>Round: {{round.name}}</h3> <div ng-repeat="teamname in round.matches | filter:namesearch"> <b>Match Date:</b> {{teamname.date}} <a ng-href="#!/15/{{teamname.date}}/{{teamname.team1.code}}/{{teamname.team2.code}}">{{teamname.team1.name}} <strong>V/S</strong> {{teamname.team2.name}}</a> </div> 无法处理字符串。

其他参考:Edwin Thoen的blog post

1 个答案:

答案 0 :(得分:1)

简答:是的。

如果您希望sym超过列,sym是一个很好的方法。 Lionel Henry在draft vignette中展示quo

如果您想传递列名但不想尝试迭代,KirillMüllerprefers library(dplyr) x <- rlang::quo(cyl) y <- rlang::sym("cyl") identical(group_by(mtcars, !!x), group_by(mtcars, !!y)) # TRUE 。在下面的示例中,它们具有相同的效果。

let dataParameters: Data = NSKeyedArchiver.archivedData(withRootObject: newParameters)