R 使用正则表达式查找 mutate 中的值

R using regular expression to look up values in mutate

我有一个参考 table,它有 2 列,例如:

pattern name
a.*b name 1
c\d{2} name 2

假设我有一个包含列 col 的数据框,如下所示:

col
adb
c12
add

我想使用模式并基于模式创建另一个基于列的列。

使用上面的例子,新列的值应该分别是 c("name 1", "name 2", NA)。我尝试编写一个带有字符串检测的循环,如下所示:

regex_map <- function(in_string){
  ref_table <- read_excel("./data/meta_data.xlsx", "mapping_ex") %>% filter(!is.na(pattern))
  
  for(i in 1:nrow(ref_table)){
    r <- ref_table[i,] 
    #print(str(r))
    if(str_detect(tolower(in_string), r$pattern)){
      return(r$name)
    }
  }
  
  return("N/A")
}

函数工作正常,但是,如果我将函数作为 mutate 的一部分,它会非常慢,这可能与预期的一样。我想知道如何在 R 中有效地执行此操作?感谢您的帮助!!

该函数非常慢,因为您每次调用它时都在读取 ref_table。仅在 mutate 之外读取文件一次,并将其作为第二个函数 regex_map 参数传递。
您可以通过在循环外仅使用一次 in_string 全部小写来进一步加快循环。
我正在使用 base::grep,而不是 stringr::str_detect

y <- '
col
adb
c12
add'
df1 <- read.table(textConnection(y), header = TRUE)

suppressPackageStartupMessages({
  library(dplyr)
  library(readxl)
})

regex_map <- function(in_string, ref_table){
  res <- rep("N/A", length(in_string))
  in_string <- tolower(in_string)
  for(i in seq_len(nrow(ref_table))){
    r <- ref_table[i, , drop = FALSE] 
    found <- grep(r$pattern, in_string)
    if(length(found)){
      res[found] <- r$name
    }
  }
  res
}

ref_table_file <- file.path("~", "Temp", "meta_data.xlsx")
ref_table <- read_excel(ref_table_file, "mapping_ex") %>% filter(!is.na(pattern))

df1 %>%
  mutate(clean = regex_map(col, ref_table))
#>   col  clean
#> 1 adb name 1
#> 2 c12 name 2
#> 3 add    N/A

reprex package (v2.0.1)

创建于 2022-05-02

另一种可能的解决方案,基于tidyverse

library(tidyverse)

df1 <- data.frame(
  pattern = c("a.*b", "c\d{2}"),
  name = c("name1", "name2")
)

df2 <- data.frame(
  col = c("adb", "c12", "add")
)

df2 %>% 
  rowid_to_column() %>% 
  full_join(df1 %>% rowid_to_column()) %>% 
  mutate(name = if_else(str_detect(col, pattern), name, NA_character_)) %>% 
  select(col, name)

#> Joining, by = "rowid"
#>   col  name
#> 1 adb name1
#> 2 c12 name2
#> 3 add  <NA>