首页 > 解决方案 > 使用 stringr::str_extract 将参数传递给包含 dplyr 管道表达式 group_by 的函数

问题描述

我想根据子字符串按组汇总以下数据:

df <- tribble(
  ~sometext, ~somevalue,
  "Kardiochirurgia",  120,
  "Kardiologia",      240,
  "Ortopedia onkologiczna",        120,
  "Kardiochirurgia onkologiczna", 300,
  "Ortopedia i traumatologia",110,
  "Urologia", 80
)

这是我想分组的子字符串:

categories <- c("kardio","orto", "uro")

以下代码有效,我会重复使用它,所以我想把它变成一个函数:

df %>% 
  group_by(categories=
    str_extract(
      string = str_to_lower(.$sometext),
      pattern = paste0(categories, collapse="|"))) %>% 
  summarise(somevalue = sum(somevalue))

该脚本完全符合我的预期:

# # A tibble: 3 x 2
# categories somevalue
# <chr>          <dbl>
# 1 kardio           660
# 2 orto             230
# 3 uro               80

我把它变成一个函数后,它不起作用:

group_by_str <- function(df, strings, patterns) {
  df %>% 
    group_by(categories=
               str_extract(
                 string = str_to_lower(.[,{{strings}}]),
                 pattern = paste0(patterns, collapse="|"))) 
   return(df)
}

双括号字符串是我的尝试之一,我首先尝试没有,尝试传递带引号的名称等无济于事。尝试在数据集上使用它:

df %>% group_by_str(strings=sometext, patterns= categories) %>% summarise(somevalue = sum(somevalue))

返回错误,显然它不知道 'strings' 是包含字符串的列的名称。在这种情况下,将列名传递给函数的正确方法应该是什么?

错误消息表明 R 可以看到列的内容并尝试将其视为列名:

 Error: Can't find columns `Kardiochirurgia`, `Kardiologia`, `Ortopedia onkologiczna`, `Kardiochirurgia onkologiczna`, `Ortopedia i traumatologia`, … (and 1 more) in `.data`.
Run `rlang::last_error()` to see where the error occurred. 

如果我删除大括号,错误说 R 看不到sometextDF 中存在的列名:

Error in check_names_df(j, x) : object 'sometext' not found

标签: rdplyrtidyverserlang

解决方案


通过一些修改,我们可以使用以下代码。

  1. 我们不需要评估patterns(添加这一点是因为我也想过tidy eval评估patterns)。

  2. 我们可以strings>=0.4.0{{}}进行评估。rlang

  3. 我们不需要return声明

  4. 我们可以在函数中做所有事情(包括摘要)

修改后的代码:

group_by_str <- function(df, strings, patterns) {
  df %>% 
    group_by(categories=
               str_extract(
                 string = str_to_lower({{strings}}),
                 pattern = paste0(patterns, 
                                          collapse="|"))) %>%

    summarise(somevalue = sum(somevalue)) 

} 


  group_by_str(df,strings=sometext, patterns= categories) 

管道友好:

 df %>% 
  group_by_str(strings=sometext, patterns= categories)

结果:

# A tibble: 3 x 2
  categories somevalue
  <chr>          <dbl>
1 kardio           660
2 orto             230
3 uro               80

推荐阅读