我想定义一个自定义函数,该函数使用dplyr对一些数据进行分组和总结,并且以布尔标志为条件可以按额外级别分组.我可以用一个完整的if...else控制块,如本例所示:

library(tidyverse)
data(Titanic)

Titanic <- as_tibble(Titanic)

foo <- function(by_age = FALSE) {
  if (by_age) {
    bar <- Titanic %>%
      group_by(Survived, Age)
  } else {
    bar <- Titanic %>%
      group_by(Survived)
  }
  
  bar %>%
    summarise(n = sum(n))
}

foo()
foo(by_age = TRUE)

但这似乎是一种非常笨拙的方法.Is there a way I can achieve this with a single block of dplyr code, conditionally calling Age as a second grouping variable?我在我的group_by声明中try 了ifelse(by_age, Age, NA),在this SO post中列出了一些技巧,但没有用.

推荐答案

编辑

对不起,我没有读到你的帖子;如果出于某种原因想要避免...方法,这是一个潜在的解决方案:

library(tidyverse)
data(Titanic)

Titanic <- as_tibble(Titanic)

foo <- function(by_age = FALSE) {
  Titanic %>%
    group_by(Survived, if(by_age) Age) %>%
    summarise(n = sum(n))
}

foo()
#> # A tibble: 2 × 2
#>   Survived     n
#>   <chr>    <dbl>
#> 1 No        1490
#> 2 Yes        711
foo(by_age = TRUE)
#> `summarise()` has grouped output by 'Survived'. You can override using the
#> `.groups` argument.
#> # A tibble: 4 × 3
#> # Groups:   Survived [2]
#>   Survived `if (by_age) Age`     n
#>   <chr>    <chr>             <dbl>
#> 1 No       Adult              1438
#> 2 No       Child                52
#> 3 Yes      Adult               654
#> 4 Yes      Child                57

reprex package(v2.0.1)于2022-07-07创建

为了避免"年龄"列被称为"if(by_Age)Age",您可以使用:

library(tidyverse)
data(Titanic)

Titanic <- as_tibble(Titanic)

foo <- function(by_age = FALSE) {
  Titanic %>%
    group_by(Survived, !!sym(ifelse(by_age, "Age", ""))) %>%
    summarise(n = sum(n))
}

foo()
#> # A tibble: 2 × 2
#>   Survived     n
#>   <chr>    <dbl>
#> 1 No        1490
#> 2 Yes        711
foo(by_age = TRUE)
#> `summarise()` has grouped output by 'Survived'. You can override using the
#> `.groups` argument.
#> # A tibble: 4 × 3
#> # Groups:   Survived [2]
#>   Survived Age       n
#>   <chr>    <chr> <dbl>
#> 1 No       Adult  1438
#> 2 No       Child    52
#> 3 Yes      Adult   654
#> 4 Yes      Child    57

reprex package(v2.0.1)于2022-07-07创建

原始答案

一种解决方案是在需要时使用... (dot-dot-dot)传递参数,例如.

library(tidyverse)
data(Titanic)

Titanic <- as_tibble(Titanic)

foo <- function(...) {
  Titanic %>%
      group_by(Survived, ...) %>%
    summarise(n = sum(n))
}

foo()
#> # A tibble: 2 × 2
#>   Survived     n
#>   <chr>    <dbl>
#> 1 No        1490
#> 2 Yes        711
foo(Age)
#> `summarise()` has grouped output by 'Survived'. You can override using the
#> `.groups` argument.
#> # A tibble: 4 × 3
#> # Groups:   Survived [2]
#>   Survived Age       n
#>   <chr>    <chr> <dbl>
#> 1 No       Adult  1438
#> 2 No       Child    52
#> 3 Yes      Adult   654
#> 4 Yes      Child    57

# You can also pass in multiple 'extra' arguments
foo(Age, Sex)
#> `summarise()` has grouped output by 'Survived', 'Age'. You can override using
#> the `.groups` argument.
#> # A tibble: 8 × 4
#> # Groups:   Survived, Age [4]
#>   Survived Age   Sex        n
#>   <chr>    <chr> <chr>  <dbl>
#> 1 No       Adult Female   109
#> 2 No       Adult Male    1329
#> 3 No       Child Female    17
#> 4 No       Child Male      35
#> 5 Yes      Adult Female   316
#> 6 Yes      Adult Male     338
#> 7 Yes      Child Female    28
#> 8 Yes      Child Male      29

reprex package(v2.0.1)于2022-07-07创建

注意:使用...有两个缺点:

  • 当您使用它将参数传递给另一个函数时,您必须仔细地向用户解释这些参数的go 向.这使得您很难理解使用lappy()和plot()等函数可以做什么.
  • 拼写错误的参数不会引发错误.这使得打字容易被忽视(从高级R;https://adv-r.hadley.nz/functions.html?q=...#fun-dot-dot-dot)

R相关问答推荐

这两种创建S4对象的方法有何不同?

使用gggplot 2在R中正确表示翻转堆叠条形图中的数据

如何设置搜索栏来搜索整个Shiny应用程序页面?

在处理因素时,Base R grep家族比stringr变体快得多

使用rlang s arg_match判断函数输入列表

使用预定值列表将模拟数量(n)替换为rnorm()

R:连接值,而不是变量?

如何计算R数据集中每个女性的子元素数量?

如何在emmeans中计算连续变量的对比度

用值序列对行进行子集化,并标识序列开始的列

gganimate在使用shadow_mark选项时不保留所有过go 的标记

如何在ggplot中标记qqplot上的点?

根据日期从参考帧中创建不同的帧

使用rest从header(h2,h3,table)提取分层信息

将重复项转换为NA

以NA为通配符的R中的FULL_JOIN以匹配其他数据中的任何值.Frame

R如何计算现有行的总和以添加新的数据行

如何在使用Alpha时让geom_curve在箭头中显示恒定透明度

ggplot斜体轴刻度标签中的单个字符-以前的帖子建议不工作

按组使用dummy r获取高于标准的行的平均值