将参数传递给包含 dplyr 管道表达式 group_by 和 stringr::str_extract 的函数

Pass argument to a function containing dplyr piped expression group_by with stringr::str_extract

我想根据子字符串分组总结以下数据:

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))

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

# # 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))

returns一个错误,显然它不知道'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 看不到 DF 中存在的 sometext 列名称:

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

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

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

  2. 我们可以用{{}}rlang计算strings>=0.4.0

  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