【问题标题】:How can I write a tidyverse-friendly function that respects group_by() earlier in the pipe?如何在管道中更早地编写一个尊重 group_by() 的 tidyverse 友好函数?
【发布时间】:2021-02-22 18:28:19
【问题描述】:

我已经开始编写函数以加快表格生成速度,但希望该函数尊重用户在管道中做出的早期分组选择。

示例数据:

df<-data.frame(ID=c("A","B","C","A","C","D","A","C","E","B","C","A"),
           Year=c(1,1,1,2,2,2,3,3,3,4,4,4),
           Credits=c(1,3,4,5,6,7,2,1,1,6,1,2),
           Major=c("GS","GS","LA","GS","GS","LA","GS","LA","LA","GS","LA","LA"),
           Status=c("green","blue","green","blue","green","blue","green","blue","green","blue","green","blue"),
           Group=c("Art","Music","Science","Art","Music","Science","Art","Music","Science","Art","Music","Science"))

以下是我正在处理的函数,它需要/接受一个变量来定义同类群组、一个信用变量和一个术语变量。

table_headsfte_cohorts<-function(.data,cohortvar,credits,term){


  cohortvar<-rlang::ensym(cohortvar)
  credits<-rlang::ensym(credits)
  term<-rlang::ensym(term)


  .data%>%
    group_by(!!term,Pidm)%>%
    group_by(!!term,!!cohortvar,group_cols())%>%
    mutate(on3=1)%>%
    mutate(`Headcount`=sum(on3),
          `FTE`=round(sum(na.omit(!!credits))/15,1))%>%
    mutate(Variable=paste0(cohortvar))%>%
    mutate(Category=!!cohortvar)%>%
    select(-!!cohortvar)%>%
    select(Variable,Category,Headcount,FTE,group_cols())
}

对于可能有兴趣在他们选择的同类群组变量之外使用其他分组变量的用户,我希望最终结果函数允许如下使用:

df2<-df%>%
 group_by(Status,Group)%>%
 table_headsfte_cohorts(Major,Credits,Year)

除了来自table_headsfte_cohorts() 参数的cohortvarterm 列之外,所需的最终结果将是一个尊重并保留上述group_by 语句中两个分组变量级别的表。

我需要生成同一张表,但是对于范围广泛的分组变量和不同数量的分组变量,灵活性会非常有帮助。

编辑:

通过至少允许多个分组变量,以下似乎接近。这不是我所希望的,因为我更喜欢从管道中读取额外的分组参数:

 table_headsfte_cohorts<-function(.data,cohortvar,credits,term,...){

  grps<-enquos(...)

  cohortvar<-rlang::ensym(cohortvar)
  credits<-rlang::ensym(credits)
  term<-rlang::ensym(term)


  .data%>%
      group_by(!!term,!!cohortvar,!!! grps)%>%
     mutate(on3=1)%>%
     mutate(`Headcount`=sum(on3),
          `FTE`=round(sum(na.omit(!!credits))/15,1))%>%
     mutate(Variable=paste0(cohortvar))%>%
     mutate(Category=!!cohortvar)%>%
     select(-!!cohortvar)%>%
     select(Variable,Category,Headcount,FTE,!!!grps)

}

使用上面,我可以成功运行:

fdfout<-fdf%>%
table_headsfte_cohorts(Major, Credits, Year), getting:

我还可以将其他变量传递给函数作为附加分组变量:

fdfout_alt<-fdf%>%
  table_headsfte_cohorts(Major,Credits,Year,Status,Group)

产生期望的结果:

不幸的是,当我使用

fdf_no<-fdf%>%
  group_by(Status, Group)%>%
  table_headsfte_cohorts(Major, Credits, Year)

我明白了:

这个输出可能会让使用我的函数的人感到困惑,因为他们的 group_by() 行似乎什么也没做。

【问题讨论】:

  • See here 关于制作一个更易于人们帮助的可重现示例。如果没有重新创建设置的示例数据,很难确切知道您要做什么以及您可能会卡在哪里
  • @camille 谢谢你的建议。我已经更新了这个问题,并希望它更清楚。如果您有机会查看并发现仍不清楚,请告诉我可能缺少什么。

标签: r dplyr tidyr


【解决方案1】:

我添加了一些行,将现有的分组变量和点内的新分组变量合并为一个字符向量。我们可以使用group_vars 获取现有的分组变量。要将新旧合并在一起,我们必须获取带引号的分组变量的表达式get_expr 并将它们转换为字符串。我们可以使用!!! syms 进行评估,使用all_of 选择分组变量。

这是你的想法吗?

table_headsfte_cohorts <- function(.data, cohortvar, credits, term, ...){
  
  new_grps <- enquos(...)
  new_grps <- purrr::map_chr(new_grps, ~ as.character(rlang::get_expr(.x)))
  ex_grps  <- group_vars(.data)
  grp_vars <- c(ex_grps, new_grps)

  cohortvar<-rlang::ensym(cohortvar)
  credits<-rlang::ensym(credits)
  term<-rlang::ensym(term)
  
  
  .data%>%
    group_by(!! term,
             !! cohortvar,
             !!! syms(grp_vars))%>%
    mutate(on3 = 1) %>%
    mutate(`Headcount`= sum(on3),
           `FTE`= round(sum(na.omit(!!credits))/15,1))%>%
    mutate(Variable=paste0(cohortvar))%>%
    mutate(Category=!!cohortvar)%>%
    select(-!!cohortvar)%>%
    select(Variable,Category,Headcount,FTE, all_of(grp_vars))
  
}

df %>%
  group_by(Status, Group) %>%
  table_headsfte_cohorts(Major, Credits, Year)

#> Adding missing grouping variables: `Major`
#> Adding missing grouping variables: `Year`, `Major`
#> # A tibble: 12 x 8
#> # Groups:   Year, Major, Status, Group [12]
#>     Year Major Variable Category Headcount   FTE Status Group  
#>    <dbl> <chr> <chr>    <chr>        <dbl> <dbl> <chr>  <chr>  
#>  1     1 GS    Major    GS               1   0.1 green  Art    
#>  2     1 GS    Major    GS               1   0.2 blue   Music  
#>  3     1 LA    Major    LA               1   0.3 green  Science
#>  4     2 GS    Major    GS               1   0.3 blue   Art    
#>  5     2 GS    Major    GS               1   0.4 green  Music  
#>  6     2 LA    Major    LA               1   0.5 blue   Science
#>  7     3 GS    Major    GS               1   0.1 green  Art    
#>  8     3 LA    Major    LA               1   0.1 blue   Music  
#>  9     3 LA    Major    LA               1   0.1 green  Science
#> 10     4 GS    Major    GS               1   0.4 blue   Art    
#> 11     4 LA    Major    LA               1   0.1 green  Music  
#> 12     4 LA    Major    LA               1   0.1 blue   Science

【讨论】:

  • 这个功能如我所愿,并保留group_by。我不需要... 来接受更多分组变量。我最终选择了ex_grps &lt;- group_vars(.data) 并将其更改为grp_vars&lt;-group_vars(.data),在我的用例中省略了new_grps
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-25
相关资源
最近更新 更多