You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于tidyeval的R自定义函数如何提取分组参数并实现多层级分组小计

实现方案

我们可以借助rlang::eval_select捕获用户传入的分组变量对应的列名,再基于分组数量动态生成多层小计结果,最后合并排序输出即可。

问题1解答:提取grps参数的第一个列名

你可以用rlang::eval_select直接解析用户传入的tidy选择语法,拿到所有分组变量的有序字符串向量,直接取第一位即可使用:

# 放在函数内部即可捕获分组列名
grp_names <- names(rlang::eval_select(rlang::expr({{ grps }}), mtcars))
# 第一个分组列名
first_grp <- grp_names[1]

后续操作该列时,既可以用.data[[first_grp]]的方式引用,也可以在mutate中用:=赋值。

问题2解答:支持3个及以上分组变量的通用实现

通用逻辑如下:

  1. 先计算所有分组维度的明细统计结果,同时把所有分组列转成字符型,避免后续插入total时出现类型冲突
  2. 如果开启小计,按「去掉最后1个分组→去掉最后2个分组→…→只剩第1个分组」的规则逐层计算小计,每一层的小计结果都将被去掉的分组列赋值为total
  3. 合并明细和所有小计结果,按分组列排序,保证total行固定出现在对应分组的末尾

完整可运行代码如下:

library(dplyr)
library(rlang)

test_function <- function(grps, subtotalrows = TRUE){
  # 捕获所有分组列名,顺序和用户传入一致
  grp_names <- names(eval_select(expr({{ grps }}), mtcars))
  n_grp <- length(grp_names)
  
  # 计算明细统计结果,分组列转字符避免类型冲突
  grouped_result <- mtcars %>% 
    group_by(across({{ grps }})) %>% 
    summarise(Count = n(), .groups = "drop") %>% 
    mutate(across(all_of(grp_names), as.character))
  
  if(!subtotalrows || n_grp == 1){
    return(grouped_result)
  }
  
  # 动态生成各层小计结果
  subtotal_list <- lapply(1:(n_grp-1), function(i){
    # 当前层要保留的前N个分组
    keep_grps <- grp_names[1:(n_grp - i)]
    # 当前层要设为total的分组
    total_grps <- setdiff(grp_names, keep_grps)
    
    mtcars %>% 
      group_by(across(all_of(keep_grps))) %>% 
      summarise(Count = n(), .groups = "drop") %>% 
      mutate(across(all_of(keep_grps), as.character)) %>% 
      # 被去掉的分组统一赋值为total
      bind_cols(!!!setNames(rep("total", length(total_grps)), total_grps)) %>% 
      select(all_of(grp_names), Count)
  })
  
  # 合并明细+所有小计,按分组列排序
  bind_rows(grouped_result, !!!subtotal_list) %>% 
    arrange(!!!syms(grp_names))
}

运行测试

双分组测试(和预期结果一致)

test_function(grps = c(cyl, gear), subtotalrows = TRUE)

输出:

# A tibble: 11 × 3
   cyl   gear  Count
   <chr> <chr> <int>
 1 4     3         1
 2 4     4         8
 3 4     5         2
 4 4     total    11
 5 6     3         2
 6 6     4         4
 7 6     5         1
 8 6     total     7
 9 8     3        12
10 8     5         2
11 8     total    14

三分组测试(自动生成两层小计)

test_function(grps = c(cyl, gear, carb), subtotalrows = TRUE)

输出会包含三类结果:cyl+gear+carb的明细行、cyl+gear维度的小计(carb为total)、cyl维度的小计(gear和carb为total)。


内容的提问来源于stack exchange,提问作者mafiale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 09:33:01