如何在dplyr中避免使用省略号…?

huangapple go评论85阅读模式
英文:

How to avoid ellipsis ... in dplyr?

问题

我想创建一个接受分组参数的函数。它可以是单个或多个变量。我希望它看起来像这样:

```R
wanted <- function(data, groups, other_params){
  data %>% group_by( {{groups}} ) %>% count()
}

这只在给定单个组时有效,但在存在多个组时会出错。我知道可以使用省略号 ... 来实现以下功能(但我想要的语法是 groups = something):

not_wanted <- function(data, ..., other_params){
  data %>% group_by( ... ) %>% count()
}

以下是完整的代码:

library(dplyr)
library(magrittr)

iris$group2 <- rep(1:5, 30)

wanted <- function(data, groups, other_params){
  data %>% group_by( {{groups}} ) %>% count()
}

not_wanted <- function(data, ..., other_params){
  data %>% group_by( ... ) %>% count()
}

# 正常运行
wanted(iris, groups = Species )
not_wanted(iris, Species, group2)

# 无法正常运行
wanted(iris, groups = vars(Species, group2) )
wanted(iris, groups = c(Species, group2) )
wanted(iris, groups = vars("Species", "group2") )
#  Error: Column `vars(Species, group2)` must be length 150 (the number of rows) or one, not 2

<details>
<summary>英文:</summary>

I want to create a function that takes a grouping argument. Which can be a single or multiple variables. I want it to look like this:

wanted <- function(data, groups, other_params){
data %>% group_by( {{groups}} ) %>% count()
}


This work only when a single group is given but breaks when there are multiple groups. I know it&#39;s possible to use the following with ellipsis `...` (But I want the syntax `groups = something`):

not_wanted <- function(data, ..., other_params){
data %>% group_by( ... ) %>% count()
}


Here is the entire code:

library(dplyr)
library(magrittr)

iris$group2 <- rep(1:5, 30)

wanted <- function(data, groups, other_params){
data %>% group_by( {{groups}} ) %>% count()
}

not_wanted <- function(data, ..., other_params){
data %>% group_by( ... ) %>% count()
}

works

wanted(iris, groups = Species )
not_wanted(iris, Species, group2)

doesn't work

wanted(iris, groups = vars(Species, group2) )
wanted(iris, groups = c(Species, group2) )
wanted(iris, groups = vars("Species", "group2") )

Error: Column vars(Species, group2) must be length 150 (the number of rows) or one, not 2

答案1

得分: 5

你们把事情弄得太复杂了,这样就可以正常工作:

library(tidyverse)

wanted <- function(data, groups){
  data %>% count(!!!groups)
}

mtcars %>% wanted(groups = vars(mpg, disp, hp))

一个 tibble: 31 x 4

 mpg  disp    hp     n


1 10.4 460 215 1
2 10.4 472 205 1
3 13.3 350 245 1
4 14.3 360 245 1
5 14.7 440 230 1
6 15 301 335 1
7 15.2 276. 180 1
8 15.2 304 150 1
9 15.5 318 150 1
10 15.8 351 264 1

… 其他 21 行

英文:

You guys are over complicating things, this works just fine:

library(tidyverse)

wanted &lt;- function(data, groups){
  data %&gt;%  count(!!!groups)
}

mtcars %&gt;% wanted(groups = vars(mpg,disp,hp))

# A tibble: 31 x 4
     mpg  disp    hp     n
   &lt;dbl&gt; &lt;dbl&gt; &lt;dbl&gt; &lt;int&gt;
 1  10.4  460    215     1
 2  10.4  472    205     1
 3  13.3  350    245     1
 4  14.3  360    245     1
 5  14.7  440    230     1
 6  15    301    335     1
 7  15.2  276.   180     1
 8  15.2  304    150     1
 9  15.5  318    150     1
10  15.8  351    264     1
# … with 21 more rows

答案2

得分: 0

三重感叹号运算符和rlang包中的parse_quos函数将起作用。有关更多信息,请参见 https://stackoverflow.com/a/49941635/6086135

library(dplyr)
library(magrittr)

iris$group2 <- rep(1:5, 30)

vec <- c("Species", "group2")

wanted <- function(data, groups){
  data %>%  count(!!!rlang::parse_quos(groups, rlang::current_env()))
}

wanted(iris, vec)
#> # A tibble: 15 x 3
#>    Species    group2     n
#>    <fct>       <int> <int>
#>  1 setosa          1    10
#>  2 setosa          2    10
#>  3 setosa          3    10
#>  4 setosa          4    10
#>  5 setosa          5    10
#>  6 versicolor      1    10
#>  7 versicolor      2    10
#>  8 versicolor      3    10
#>  9 versicolor      4    10
#> 10 versicolor      5    10
#> 11 virginica       1    10
#> 12 virginica       2    10
#> 13 virginica       3    10
#> 14 virginica       4    10
#> 15 virginica       5    10

# Created on 2020-01-06 by the reprex package (v0.3.0)
英文:

The triple bang operator and parse_quos from the rlang package will do the trick. For more info, see e.g. https://stackoverflow.com/a/49941635/6086135

<!-- language-all: lang-r -->

library(dplyr)

library(magrittr)

iris$group2 &lt;- rep(1:5, 30)


vec &lt;- c(&quot;Species&quot;, &quot;group2&quot;)


wanted &lt;- function(data, groups){
  data %&gt;%  count(!!!rlang::parse_quos(groups, rlang::current_env()))
}

wanted(iris, vec)
#&gt; # A tibble: 15 x 3
#&gt;    Species    group2     n
#&gt;    &lt;fct&gt;       &lt;int&gt; &lt;int&gt;
#&gt;  1 setosa          1    10
#&gt;  2 setosa          2    10
#&gt;  3 setosa          3    10
#&gt;  4 setosa          4    10
#&gt;  5 setosa          5    10
#&gt;  6 versicolor      1    10
#&gt;  7 versicolor      2    10
#&gt;  8 versicolor      3    10
#&gt;  9 versicolor      4    10
#&gt; 10 versicolor      5    10
#&gt; 11 virginica       1    10
#&gt; 12 virginica       2    10
#&gt; 13 virginica       3    10
#&gt; 14 virginica       4    10
#&gt; 15 virginica       5    10

<sup>Created on 2020-01-06 by the reprex package (v0.3.0)</sup>

答案3

得分: 0

以下是翻译好的部分:

这是另一种避免在函数调用中使用引号的选项。我承认它并不是很漂亮。

library(tidyverse)

wanted <- function(data, groups){
  grouping <- gsub(x = rlang::quo_get_expr(enquo(groups)), pattern = "\\((.*)?\\)", replacement = "\")[-1]
  data %>% group_by_at(grouping) %>% count()
}

iris$group2 <- rep(1:5, 30)

wanted(iris, groups = c(Species, group2) )
#> # A tibble: 15 x 3
#> # Groups:   Species, group2 [15]
#>    Species    group2     n
#>    <fct>       <int> <int>
#>  1 setosa          1    10
#>  2 setosa          2    10
#>  3 setosa          3    10
#>  4 setosa          4    10
#>  5 setosa          5    10
#>  6 versicolor      1    10
#>  7 versicolor      2    10
#>  8 versicolor      3    10
#>  9 versicolor      4    10
#> 10 versicolor      5    10
#> 11 virginica       1    10
#> 12 virginica       2    10
#> 13 virginica       3    10
#> 14 virginica       4    10
#> 15 virginica       5    10

希望这对您有所帮助。

英文:

Here is another option to avoid quotations in the function call. I admit its not very pretty though.

library(tidyverse)

wanted &lt;- function(data, groups){
  grouping &lt;- gsub(x = rlang::quo_get_expr(enquo(groups)), pattern = &quot;\\((.*)?\\)&quot;, replacement = &quot;\&quot;)[-1]
  data %&gt;% group_by_at(grouping) %&gt;% count()
}


iris$group2 &lt;- rep(1:5, 30)

wanted(iris, groups = c(Species, group2) )
#&gt; # A tibble: 15 x 3
#&gt; # Groups:   Species, group2 [15]
#&gt;    Species    group2     n
#&gt;    &lt;fct&gt;       &lt;int&gt; &lt;int&gt;
#&gt;  1 setosa          1    10
#&gt;  2 setosa          2    10
#&gt;  3 setosa          3    10
#&gt;  4 setosa          4    10
#&gt;  5 setosa          5    10
#&gt;  6 versicolor      1    10
#&gt;  7 versicolor      2    10
#&gt;  8 versicolor      3    10
#&gt;  9 versicolor      4    10
#&gt; 10 versicolor      5    10
#&gt; 11 virginica       1    10
#&gt; 12 virginica       2    10
#&gt; 13 virginica       3    10
#&gt; 14 virginica       4    10
#&gt; 15 virginica       5    10

huangapple
  • 本文由 发表于 2020年1月6日 19:52:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/59611638.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定