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

如何创建可传递列参数的dplyr函数?

解决dplyr函数中传递列名参数的问题

我最近尝试写一个内部调用dplyr的函数,想要把列名作为参数传递进去,结果试了各种方法都踩坑:用enquo搭配!!、尝试用!!as_label解决前一步的错误、换group_by_替代group_by,甚至试了curly operator,全都没成功。我的测试数据和代码如下:

userMaster <- structure(list(user_id = c(1, 2, 3, 4, 5), city = structure(c(5L, 5L, 8L, 9L, 10L), .Label = c("Austin", "Boise", "Boston", "Chicago", "Dallas", "Denver", "Detroit", "Kansas City", "Las Vegas", "Los Angeles", "Manhattan", "Miami", "Minneapolis", "New York City", "Oklahoma City", "Omaha", "Phoenix", "Saint Louis", "San Francisco", "Washington DC" ), class = "factor"), source = structure(c(2L, 2L, 2L, 2L, 2L ), .Label = c("Adwords", "Organic", "Search Ads"), class = "factor")), row.names = c(NA, 5L), class = "data.frame")

userCount <- function(table, metric){
  col_enquo <- enquo(metric)
  summary <- table %>% 
    select(!! (col_enquo), source, user_id) %>% 
    group_by_(!! (col_enquo), source) %>% 
    summarise(users = n_distinct(user_id)) %>% 
    left_join(table %>% group_by(source) %>% summarise(total = n_distinct(user_id))) %>% 
    mutate(users/total)
  return(summary)
}

genderDemo <- userCount(userMaster, city)

遇到的错误包括:

Error: quos(desire) must evaluate to column positions or names, not a list
Error in !as_label(col_enquo) : invalid argument type
Error: Quosures can only be unquoted within a quasiquotation context. # Bad: list(!!myquosure) # Good: dplyr::mutate(data, !!myquosure)

问题根源

核心问题是你混合了dplyr的旧版标准评估语法(比如group_by_这类带下划线的函数)和新版非标准评估语法(enquo+!!),这两种语法体系不能混用,会导致参数解析冲突。另外,现在dplyr的核心函数都已经原生支持非标准评估,不需要切换到旧版函数。

修正后的解决方案

现在dplyr推荐用更简洁的{{}}(curly curly)语法,它是enquo+!!的语法糖,用起来更直观。当然你也可以继续用enquo+!!的组合,只要统一语法即可。

方案1:使用{{}}语法(推荐)

userCount <- function(table, metric){
  summary <- table %>% 
    select({{metric}}, source, user_id) %>% 
    group_by({{metric}}, source) %>% 
    summarise(users = n_distinct(user_id), .groups = "drop") %>% 
    left_join(table %>% 
                group_by(source) %>% 
                summarise(total = n_distinct(user_id), .groups = "drop")) %>% 
    mutate(ratio = users/total)  # 给计算列命名,避免默认的V1列名
  return(summary)
}

# 调用测试
genderDemo <- userCount(userMaster, city)
print(genderDemo)

方案2:使用enquo+!!语法

userCount <- function(table, metric){
  col_enquo <- enquo(metric)
  summary <- table %>% 
    select(!!col_enquo, source, user_id) %>% 
    group_by(!!col_enquo, source) %>% 
    summarise(users = n_distinct(user_id), .groups = "drop") %>% 
    left_join(table %>% 
                group_by(source) %>% 
                summarise(total = n_distinct(user_id), .groups = "drop")) %>% 
    mutate(ratio = users/total)
  return(summary)
}

genderDemo <- userCount(userMaster, city)
print(genderDemo)

额外优化说明

  1. 给mutate的计算列添加了ratio作为列名,避免生成默认的V1列,让结果更清晰;
  2. 在summarise中加入.groups = "drop",可以消除dplyr的分组残留警告,同时让输出结果更整洁;
  3. 彻底弃用了group_by_这类旧版函数,统一使用新版非标准评估语法,避免语法冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:46:24