如何在R函数中实现dataframe动态group_by并适配complete函数
实现方案
我们可以通过tidy evaluation的动态参数展开能力实现需求,不用硬编码列名,支持任意数量的分组列和对应自定义取值范围:
完整函数代码
library(dplyr) library(tidyr) # 测试数据 df <- data.frame(col_a = sample(1:10, 100, replace = T), col_b = sample(letters, 100, replace = T), col_c = sample(LETTERS, 100, replace = T)) # 自定义函数 my_fun <- function(df, group_cols, fill_levels) { # 分组聚合 df %>% group_by(across(all_of(group_cols))) %>% summarise(count = n(), .groups = "drop") %>% # 动态展开fill_levels为complete的参数 complete(!!!fill_levels, fill = list(count = 0)) }
调用示例
# 按col_a、col_b分组,指定对应完整取值 my_fun( df = df, group_cols = c("col_a", "col_b"), fill_levels = list(col_a = 1:10, col_b = letters) ) # 按col_a、col_b、col_c分组,指定三列的完整取值 my_fun( df = df, group_cols = c("col_a", "col_b", "col_c"), fill_levels = list(col_a = 1:10, col_b = letters, col_c = LETTERS) ) # 仅按col_a分组的场景 my_fun( df = df, group_cols = "col_a", fill_levels = list(col_a = 1:10) )
核心逻辑说明
group_cols参数传入字符向量格式的分组列名,across(all_of())适配动态列名的分组需求,替换了已经过时的group_by_写法,兼容性更强fill_levels传入命名列表,键对应分组列名,值对应该列需要补全的所有取值!!!是rlang的动态参数展开操作符,会把fill_levels列表的所有元素直接作为参数传递给complete,完全适配任意数量的分组列场景
可选适配:保持原调用格式
如果你想和原代码一样用...直接传分组列,可以用如下写法:
my_fun <- function(df, ..., fill_levels) { group_cols <- sapply(ensyms(...), as.character) df %>% group_by(across(all_of(group_cols))) %>% summarise(count = n(), .groups = "drop") %>% complete(!!!fill_levels, fill = list(count = 0)) } # 调用方式和原代码习惯一致 my_fun(df, col_a, col_b, fill_levels = list(col_a = 1:10, col_b = letters))
内容的提问来源于stack exchange,提问作者Allerious
相关产品推荐
相关产品推荐

