如何在dplyr的summarise中复用自定义分组汇总函数
问题描述
我有一个数据框,需要应用自定义分组汇总逻辑:如果每组的最大值大于等于指定阈值,就用该组的最大值;否则用平均值。初始实现代码如下:
library(tidyverse) dat <- data.frame(grp = c("a", "a", "a", "b", "b"), vals = c(115, 100, 101, 90, 100)) dat %>% group_by(grp) %>% summarise(new_val = case_when(max(vals) >= 100 ~ max(vals), TRUE ~ mean(vals)))
但我想复用这个逻辑,并且能灵活更换阈值,不想重复硬编码。尝试了以下自定义函数但无法运行:
sumFunc <- function(max_val) { case_when(max(vals) >= max_val ~ max(vals), TRUE ~ mean(vals)) } dat %>% group_by(grp) %>% summarise(new_val = sumFunc(100))
请问如何正确创建可复用的自定义函数?
解决方案
问题根源是自定义函数未明确接收数据列参数,无法在dplyr的分组上下文里识别vals列。以下是几种可行的实现方式:
方法1:基础自定义函数(单列处理)
让函数同时接收要计算的列和阈值参数,明确在函数内部处理列数据:
sumFunc <- function(col, max_val) { col_max <- max(col, na.rm = TRUE) if (col_max >= max_val) col_max else mean(col, na.rm = TRUE) } # 使用示例(阈值100) dat %>% group_by(grp) %>% summarise(new_val = sumFunc(vals, 100)) # 更换阈值为95的示例 dat %>% group_by(grp) %>% summarise(new_val = sumFunc(vals, 95))
添加na.rm = TRUE是为了处理数据中可能存在的缺失值,提升函数鲁棒性。
方法2:适配across的函数(多列批量处理)
如果需要对多列应用该逻辑,可以编写嵌套函数配合across使用,方便批量操作:
sumFunc_across <- function(max_val) { function(col) { col_max <- max(col, na.rm = TRUE) col_max >= max_val ? col_max : mean(col, na.rm = TRUE) } } # 对vals列应用,阈值100 dat %>% group_by(grp) %>% summarise(across(vals, sumFunc_across(100), .names = "new_{col}")) # 同时对多列应用(假设数据有vals1、vals2列) # dat %>% # group_by(grp) %>% # summarise(across(c(vals1, vals2), sumFunc_across(100), .names = "new_{col}"))
方法3:支持字符串列名的函数(灵活指定列)
如果需要通过字符串传递列名,可以用rlang的准引用工具实现:
sumFunc_quo <- function(col_name, max_val) { col <- rlang::ensym(col_name) dat %>% group_by(grp) %>% summarise(new_val = case_when( max(!!col) >= max_val ~ max(!!col), TRUE ~ mean(!!col, na.rm = TRUE) )) } # 使用示例 sumFunc_quo("vals", 100)
内容的提问来源于stack exchange,提问作者DJC
相关产品推荐
相关产品推荐

