使用dplyr和NSE动态构造具有不同参数的函数调用

劳勒

我希望能够使用dplyr使用可变的分组变量/参数动态构造函数调用。函数调用的数量可能很大,这意味着使用dplyr小插图进行编程的示例不切实际。理想情况下,我希望能够事先构造一个对象(例如列表),该对象存储要在每个函数调用中传递的参数/变量。下面是一个示例数据集,我们希望在此基于更改的分组变量应用一些汇总功能。

set.seed(1)
df <- data.frame(values = sample(x = 1:10, size = 10),
                 grouping_var1 = sample(x = letters[1:2], size = 10, replace = TRUE),
                 grouping_var2 = sample(x = letters[24:26], size = 10, replace = TRUE),
                 grouping_var3 = sample(x = LETTERS[1:2], size = 10, replace = TRUE))

> df
   values grouping_var1 grouping_var2 grouping_var3
1       9             a             x             B
2       4             a             z             B
3       7             a             x             A
4       1             a             x             B
5       2             a             x             A
6       5             b             x             A
7       3             b             y             B
8      10             b             x             A
9       6             b             x             B
10      8             a             y             B

使用dplyr小插图进行编程之后,我们可以提出这样的解决方案:

f <- function(df, ...){
  group_var <- enquos(...)

  df %>%
    group_by(!!! group_var) %>%
    summarise_at(.vars = "values", .funs = sum) %>%
    print(n = 10)
}

> f(df, grouping_var1)
# A tibble: 2 x 2
  grouping_var1 values
  <fct>          <int>
1 a                 31
2 b                 24

> f(df, grouping_var1, grouping_var2)
# A tibble: 5 x 3
# Groups:   grouping_var1 [2]
  grouping_var1 grouping_var2 values
  <fct>         <fct>          <int>
1 a             x                 19
2 a             y                  8
3 a             z                  4
4 b             x                 21
5 b             y                  3

如果我要构造大量呼叫,则上面的示例不切实际且不灵活。另一个限制是,我希望包含的其他信息无法轻易地一起传递或除了分组变量之外。

假设我有一个列表,其中包含要在每个函数调用中传递的分组变量。还假定对于每个这些列表元素,都有一个单独的字段,其中带有一个“ id”来描述所执行的分组。参见以下示例:

list(group_vars = list(c("grouping_var1"),
                       c("grouping_var1", "grouping_var2"),
                       c("grouping_var1", "grouping_var3")),
     group_ids = list("var_1",
                      c("var_1_2"),
                      c("var_1_3")))

如何动态地将这些参数/变量和ID列表传递给函数调用,并使用dplyr成功评估它们?假设我要在结果数据框中创建一列,除了汇总数据之外,该列还包含group_ids。例如,如果我group_varsc("grouping_var1", "grouping_var2")group_ids"var_1_2"为特定的函数调用我期望的输出:

# A tibble: 5 x 4
# Groups:   grouping_var1 [2]
  grouping_var1 grouping_var2 values group_ids
  <fct>         <fct>          <int> <chr>    
1 a             x                 19 var_1_2  
2 a             y                  8 var_1_2  
3 a             z                  4 var_1_2  
4 b             x                 21 var_1_2  
5 b             y                  3 var_1_2 

我希望看到一个解决方案,使用如今不赞成使用的group_by_接受字符串的函数来实现此目的

最后,我感到相当沮丧的是,使用NSE在函数中使用dplyr进行编程会遇到这样的入门障碍。每当我遇到一些简单的问题,就需要花费数小时才能找到解决方案。

eipi10

我不确定这里的“标准” tidyverse方法是什么,因为当我尝试为典型的工作流程编写广义tidyverse函数时,我从来没有真正知道自己是否“做对了”,但这是另一种方法。 *

首先,我们可以生成分组列组合的列表,而不是对其进行硬编码。在这种情况下,该列表包括1、2或3个分组列的所有可能组合,但是可以根据需要进行缩减。

library(tidyverse)

# Generate a list of combinations of grouping variables.
groups.list = map(1:3, ~combn(names(df)[map_lgl(df, ~!is.numeric(.))], .x, simplify=FALSE)) %>% 
  flatten

以下是使用的摘要函数group_by_at,该函数可以接受字符串,因此不需要非标准评估。另外,我们group.idsgroup_vars自身获取,因此我们不需要单独的参数或自变量(尽管可能需要进行调整,具体取决于对分组列名称的期望)。

# Summarise for each combination of groups
# Generate group.ids from group_vars itself
f2 <- function(data, group_vars) {

  data %>%
    group_by_at(group_vars) %>%
    summarise(values=sum(values)) %>% 
    mutate(group.ids=paste0("var_", paste(str_extract(group_vars, "[0-9]"), collapse="_")))

  }

现在我们可以在每个元素上运行run函数 group.list

map(groups.list, ~f2(df, .x))
[[1]]
# A tibble: 2 x 3
  grouping_var1 values group.ids
  <fct>          <int> <chr>    
1 a                 31 var_1    
2 b                 24 var_1    

[[2]]
# A tibble: 3 x 3
  grouping_var2 values group.ids
  <fct>          <int> <chr>    
1 x                 40 var_2    
2 y                 11 var_2    
3 z                  4 var_2    

[[3]]
# A tibble: 2 x 3
  grouping_var3 values group.ids
  <fct>          <int> <chr>    
1 A                 24 var_3    
2 B                 31 var_3    

[[4]]
# A tibble: 5 x 4
# Groups:   grouping_var1 [2]
  grouping_var1 grouping_var2 values group.ids
  <fct>         <fct>          <int> <chr>    
1 a             x                 19 var_1_2  
2 a             y                  8 var_1_2  
3 a             z                  4 var_1_2  
4 b             x                 21 var_1_2  
5 b             y                  3 var_1_2  

[[5]]
# A tibble: 4 x 4
# Groups:   grouping_var1 [2]
  grouping_var1 grouping_var3 values group.ids
  <fct>         <fct>          <int> <chr>    
1 a             A                  9 var_1_3  
2 a             B                 22 var_1_3  
3 b             A                 15 var_1_3  
4 b             B                  9 var_1_3  

[[6]]
# A tibble: 4 x 4
# Groups:   grouping_var2 [3]
  grouping_var2 grouping_var3 values group.ids
  <fct>         <fct>          <int> <chr>    
1 x             A                 24 var_2_3  
2 x             B                 16 var_2_3  
3 y             B                 11 var_2_3  
4 z             B                  4 var_2_3  

[[7]]
# A tibble: 7 x 5
# Groups:   grouping_var1, grouping_var2 [5]
  grouping_var1 grouping_var2 grouping_var3 values group.ids
  <fct>         <fct>         <fct>          <int> <chr>    
1 a             x             A                  9 var_1_2_3
2 a             x             B                 10 var_1_2_3
3 a             y             B                  8 var_1_2_3
4 a             z             B                  4 var_1_2_3
5 b             x             A                 15 var_1_2_3
6 b             x             B                  6 var_1_2_3
7 b             y             B                  3 var_1_2_3

或者,如果要合并所有结果,则可以执行以下操作:

map(groups.list, ~f2(df, .x)) %>% 
  bind_rows() %>% 
  mutate_if(is.factor, fct_explicit_na, na_level="All") %>% 
  select(group.ids, matches("grouping"), values)
   group.ids grouping_var1 grouping_var2 grouping_var3 values
   <chr>     <fct>         <fct>         <fct>          <int>
 1 var_1     a             All           All               31
 2 var_1     b             All           All               24
 3 var_2     All           x             All               40
 4 var_2     All           y             All               11
 5 var_2     All           z             All                4
 6 var_3     All           All           A                 24
 7 var_3     All           All           B                 31
 8 var_1_2   a             x             All               19
 9 var_1_2   a             y             All                8
10 var_1_2   a             z             All                4
11 var_1_2   b             x             All               21
12 var_1_2   b             y             All                3
13 var_1_3   a             All           A                  9
14 var_1_3   a             All           B                 22
15 var_1_3   b             All           A                 15
16 var_1_3   b             All           B                  9
17 var_2_3   All           x             A                 24
18 var_2_3   All           x             B                 16
19 var_2_3   All           y             B                 11
20 var_2_3   All           z             B                  4
21 var_1_2_3 a             x             A                  9
22 var_1_2_3 a             x             B                 10
23 var_1_2_3 a             y             B                  8
24 var_1_2_3 a             z             B                  4
25 var_1_2_3 b             x             A                 15
26 var_1_2_3 b             x             B                  6
27 var_1_2_3 b             y             B                  3
  • 这个问题被交叉发布到RStudio社区,我也在那里添加了这个答案。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

具有不同参数的动态调用命令

来自分类Dev

从C ++ 17中的另一个构造函数调用具有不同参数类型的构造函数

来自分类Dev

在声明具有不同参数的构造函数时使用此方法

来自分类Dev

具有不同参数的调用方法

来自分类Dev

使用相同的指针指向具有不同参数的函数

来自分类Dev

使用并行包将具有不同参数的函数调用发送到R中的不同处理器

来自分类Dev

Python中具有不同参数列表的超类的构造函数

来自分类Dev

当局部定义具有不同参数的函数时,不能调用静态导入的重载函数?

来自分类Dev

在本地定义具有不同参数的函数时,不能调用静态导入的重载函数吗?

来自分类Dev

不同参数的调用函数

来自分类Dev

如何调用具有相同名称但不同参数的虚函数?

来自分类Dev

如何多次调用具有不同参数的函数成员?

来自分类Dev

CMAKE:重复调用具有不同参数的函数会得到相同的结果

来自分类Dev

如何使用具有相同参数类型的多个构造函数创建类

来自分类Dev

遍历具有不同参数的方法调用

来自分类Dev

Mockito-verifyNoMoreInteractions-具有不同参数的多个调用

来自分类Dev

具有不同参数的 Java 方法调用

来自分类Dev

具有不同参数子类型的Julia函数

来自分类Dev

具有不同参数的回调函数

来自分类Dev

C ++继承重载具有不同参数的函数

来自分类Dev

创建具有不同参数的模板函数

来自分类Dev

R函数%in%-具有相同参数的不同结果

来自分类Dev

具有不同参数子类型的Julia函数

来自分类Dev

具有不同参数传递的 Javascript 函数

来自分类Dev

键入具有任意数量不同参数的函数

来自分类Dev

如何使用单个按钮单击事件来调用具有不同参数的方法

来自分类Dev

使用moq验证具有某种方法的不同参数的多个调用

来自分类Dev

不同参数的辅助构造函数

来自分类Dev

R-使用嵌套数据框运行具有不同参数集的函数

Related 相关文章

  1. 1

    具有不同参数的动态调用命令

  2. 2

    从C ++ 17中的另一个构造函数调用具有不同参数类型的构造函数

  3. 3

    在声明具有不同参数的构造函数时使用此方法

  4. 4

    具有不同参数的调用方法

  5. 5

    使用相同的指针指向具有不同参数的函数

  6. 6

    使用并行包将具有不同参数的函数调用发送到R中的不同处理器

  7. 7

    Python中具有不同参数列表的超类的构造函数

  8. 8

    当局部定义具有不同参数的函数时,不能调用静态导入的重载函数?

  9. 9

    在本地定义具有不同参数的函数时,不能调用静态导入的重载函数吗?

  10. 10

    不同参数的调用函数

  11. 11

    如何调用具有相同名称但不同参数的虚函数?

  12. 12

    如何多次调用具有不同参数的函数成员?

  13. 13

    CMAKE:重复调用具有不同参数的函数会得到相同的结果

  14. 14

    如何使用具有相同参数类型的多个构造函数创建类

  15. 15

    遍历具有不同参数的方法调用

  16. 16

    Mockito-verifyNoMoreInteractions-具有不同参数的多个调用

  17. 17

    具有不同参数的 Java 方法调用

  18. 18

    具有不同参数子类型的Julia函数

  19. 19

    具有不同参数的回调函数

  20. 20

    C ++继承重载具有不同参数的函数

  21. 21

    创建具有不同参数的模板函数

  22. 22

    R函数%in%-具有相同参数的不同结果

  23. 23

    具有不同参数子类型的Julia函数

  24. 24

    具有不同参数传递的 Javascript 函数

  25. 25

    键入具有任意数量不同参数的函数

  26. 26

    如何使用单个按钮单击事件来调用具有不同参数的方法

  27. 27

    使用moq验证具有某种方法的不同参数的多个调用

  28. 28

    不同参数的辅助构造函数

  29. 29

    R-使用嵌套数据框运行具有不同参数集的函数

热门标签

归档