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

使用purrr与dplyr时,rlang::sym是否为最优实现方式?

关于dplyr编程中字符串变量名与tidy求值的问题解答

一、用rlang::sym()处理字符串变量名是合理的实现方式

你当前的代码不仅可行,而且是在dplyr中处理字符串形式变量名的标准方法之一,完全没问题。

rlang::sym()的作用就是把字符串转换成dplyr能识别的符号(symbol)——也就是我们平时写未引号变量名时的底层对象。配合!!(解引用运算符),就能让group_by()正确识别这个变量,完成分组操作。

不过你的输出里出现了NA,是因为map_df会自动合并结果,每个分组变量对应的结果列会在另一个分组的行里填充NA。如果想要更清晰的输出,可以给函数加一列标记分组变量名:

library(tidyverse)
my_summarise <- function(df, group_var) {
  group_sym <- rlang::sym(group_var)
  df %>% 
    group_by(!!group_sym) %>% 
    summarise(mpg = mean(mpg), .groups = "drop") %>% 
    mutate(grouped_by = group_var) # 新增列标记分组变量
}

purrr::map_df(c("cyl", "am"), my_summarise, df = mtcars)

输出会变成:

# A tibble: 5 × 3
    cyl   mpg grouped_by
  <dbl> <dbl> <chr>     
1     4  26.7 cyl       
2     6  19.7 cyl       
3     8  15.1 cyl       
4    NA  17.1 am        
5    NA  24.4 am        

另外,还有两种替代方法可以实现同样的效果,供你参考:

  • 使用.data代词:不需要转换符号,直接通过字符串索引数据框的列
    my_summarise <- function(df, group_var) {
      df %>% 
        group_by(.data[[group_var]]) %>% 
        summarise(mpg = mean(mpg), .groups = "drop") %>% 
        mutate(grouped_by = group_var)
    }
    
  • 使用across()(适合同时处理多个变量的场景):
    my_summarise <- function(df, group_var) {
      df %>% 
        group_by(across(all_of(group_var))) %>% 
        summarise(mpg = mean(mpg), .groups = "drop") %>% 
        mutate(grouped_by = group_var)
    }
    

二、为什么select(mtcars, !!x)可行但group_by(mtcars, !!x)不行?

这个差异和解引用本身无关,而是select()和group_by()的参数设计不同:

  • select()的参数非常灵活,它原生支持直接传入字符串、符号、列位置甚至选择辅助函数(比如starts_with())。所以哪怕你直接写select(mtcars, x)(不用!!),只要x是字符串,它也能正常工作。当你用!!x时,本质上还是把字符串传给了select(),而它刚好能处理。
  • group_by()的标准接口只接受符号或表达式,不支持直接传入字符串。当你写group_by(mtcars, !!x)时,x是字符串,!!x解引用后还是字符串,group_by()无法识别这个字符串对应的列,所以会报错。

要让group_by()处理字符串变量名,要么用sym()转成符号再解引用,要么用.data[[x]]的方式,这两种都是tidy求值框架下的规范写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:37:05