我希望能够使用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_vars
是c("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进行编程会遇到这样的入门障碍。每当我遇到一些简单的问题,就需要花费数小时才能找到解决方案。
我不确定这里的“标准” 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.ids
从group_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
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句