如何在dplyr的filter与summarise中使用动态变量编写R函数?
解决dplyr函数中动态变量的使用问题
我尝试用DRY原则精简R代码,但编写使用dplyr的函数时,没法正确处理动态变量。原代码如下:
calc <- function(df, count_var, sample_var, pct_var) { df %>% filter_at(vars(count_var, sample_var), all_vars(!is.na(.))) %>% group_by(dated, device_category, path) %>% summarise( .groups = "keep", total_good := sum(df[[count_var]], na.rm = TRUE), sample_var := sum(df[[sample_var]], na.rm = TRUE), pct_var := total_good / df[[sample_var]] ) } lcp <- calc(data, 'lcp_good_count', 'lcp_sample', 'lcp_good_pct')
需要修改代码,让传入的变量名能正确完成过滤和汇总计算。
修正后的代码(兼容字符串参数)
library(dplyr) calc <- function(df, count_var, sample_var, pct_var) { # 将字符串参数转换为dplyr可识别的符号 count_sym <- rlang::sym(count_var) sample_sym <- rlang::sym(sample_var) pct_sym <- rlang::sym(pct_var) df %>% # 用across替代已弃用的filter_at,处理动态列的NA过滤 filter(across(c({{count_var}}, {{sample_var}}), ~!is.na(.x))) %>% group_by(dated, device_category, path) %>% summarise( .groups = "keep", total_good := sum(!!count_sym, na.rm = TRUE), !!sample_sym := sum(!!sample_sym, na.rm = TRUE), !!pct_sym := total_good / !!sample_sym ) } # 调用函数(传入字符串参数) lcp <- calc(data, 'lcp_good_count', 'lcp_sample', 'lcp_good_pct')
关键修改说明
- 替换过时的filter_at:
filter_at已被dplyr官方弃用,改用filter(across(...))实现多列NA过滤,{{ }}语法可直接兼容字符串或裸变量形式的参数。 - 动态变量与列名处理:
- 用
rlang::sym()将字符串参数转为符号,配合!!(bang-bang操作符)在dplyr函数中引用动态变量,避免直接使用df[[var]](分组后应基于当前组数据计算,而非原数据框)。 - 通过
!!sym(var) :=的格式实现动态列命名,让传入的参数名直接成为汇总后的列名。
- 用
- 分组求和逻辑:求和时直接使用转换后的符号变量,确保计算的是当前分组内的总和,而非原数据框的全局总和。
可选:支持裸变量的简化版本
如果调用时不想加引号,可以直接用{{ }}处理裸变量:
calc <- function(df, count_var, sample_var, pct_var) { df %>% filter(across(c({{count_var}}, {{sample_var}}), ~!is.na(.x))) %>% group_by(dated, device_category, path) %>% summarise( .groups = "keep", total_good := sum({{count_var}}, na.rm = TRUE), {{sample_var}} := sum({{sample_var}}, na.rm = TRUE), {{pct_var}} := total_good / {{sample_var}} ) } # 调用时无需加引号 lcp <- calc(data, lcp_good_count, lcp_sample, lcp_good_pct)
内容的提问来源于stack exchange,提问作者purpletonic
相关产品推荐
相关产品推荐

