如何在R函数中正确引用新创建变量并传递给辅助函数?
Backtrace:
- global treemap_index1(df, region, district, sales)
- scales (local) mydollars("{{agg_number}}2")
- scales::dollar(...)
- scales::number(...)
- scales:::scale_cut(...)
- base::cut(...)
Runrlang::last_trace()to see the full context.
如果将有问题的代码替换为如下内容,函数可以正常运行: ```r treemap_index2 <- function(df, category1, category2, agg_number){ df_out <- df %>% mutate("{{category2}}.index" := paste({{category2}}, mydollars({{agg_number}}), sep = "\n")) %>% group_by({{category1}}) %>% mutate("{{agg_number}}2" := sum({{agg_number}}), "{{category1}}.index" := paste({{category1}}, "Test String", # 临时替换的代码 sep = "\n")) %>% print() return(df_out) } treemap_index2(df, region, district, sales) # A tibble: 6 × 6 # Groups: region [2] region district sales district.index sales2 region.index <chr> <chr> <dbl> <chr> <dbl> <chr> 1 North Dist-1 2000 "Dist-1\n$2 K" 1800003600 "North\nTest String" 2 South Dist-2 300001600 "Dist-2\n$300 M" 2700002400 "South\nTest String" 3 North Dist-3 600001200 "Dist-3\n$600 M" 1800003600 "North\nTest String" 4 South Dist-4 900000800 "Dist-4\n$900 M" 2700002400 "South\nTest String" 5 North Dist-5 1200000400 "Dist-5\n$1.2 B" 1800003600 "North\nTest String" 6 South Dist-6 1500000000 "Dist-6\n$1.5 B" 2700002400 "South\nTest String"
解决方案
报错的核心原因是"{{agg_number}}2"被当作字符串传递给了mydollars,而不是引用数据框中刚创建的数值变量。要解决这个问题,需要先动态生成新变量的名称,再正确引用它:
修改后的函数
treemap_index1 <- function(df, category1, category2, agg_number){ # 将参数转换为字符串,拼接得到新列名 agg_col <- rlang::as_name(enquo(agg_number)) agg_col2 <- paste0(agg_col, "2") df_out <- df %>% mutate("{{category2}}.index" := paste({{category2}}, mydollars({{agg_number}}), sep = "\n")) %>% group_by({{category1}}) %>% mutate(!!agg_col2 := sum({{agg_number}}), "{{category1}}.index" := paste({{category1}}, mydollars(.data[[agg_col2]]), # 使用.data代词引用动态列 sep = "\n")) return(df_out) } # 测试函数 treemap_index1(df, region, district, sales)
关键说明
- 动态生成列名:用
rlang::as_name(enquo(agg_number))把输入的参数转换为字符串,再拼接"2"得到聚合后的列名agg_col2。 - 引用动态列:使用
.data[[agg_col2]]来访问新创建的列,这是tidyverse中推荐的动态引用列的方式,避免字符串直接传递导致的类型错误。 - 创建动态列:用
!!agg_col2 := sum({{agg_number}})来创建带后缀的聚合列,!!用于将字符串转换为变量名。
代码优化建议
- 去掉函数内的
print(),让返回的数据框由用户自行决定是否打印,保持函数的纯粹性。 - 用
glue::glue替代paste,让字符串拼接更直观:mutate("{{category2}}.index" := glue::glue("{category2}\n{mydollars(agg_number)}")) - 可以添加参数来自定义后缀(比如把"2"作为可选参数),进一步提升函数的复用性。
内容的提问来源于stack exchange,提问作者ScottyJ
相关产品推荐
相关产品推荐

