R - 找到包含所有搜索词的向量元素的快速方法

3

我在这里找到了同样的问题的答案: R - 查找包含所有字符串/模式的向量元素 - str_detect grep。但建议的解决方案执行时间过长。

我有73,360个带有句子的观测值。我想要一个TRUE返回匹配,包含所有搜索字符串。

sentences <- c("blue green red",
               "blue green yellow",
               "green red  yellow ")
search_terms <- c("blue","red")

pattern <- paste0("(?=.*", search_terms,")", collapse="") 
grepl(pattern, sentences, perl = TRUE)

-output

[1]  TRUE FALSE FALSE

这样可以得到正确的结果,但是耗时非常非常长。有更快的方法吗? 我尝试了 str_detect ,但得到相同的延迟结果。
顺便说一下,“句子”包含特殊字符,例如[],.-,但没有像ñ这样的特殊字符。
更新:以下是使用建议方法的基准测试结果,感谢 @onyambu 的输入。
Unit: milliseconds
                  expr       min        lq      mean    median        uq      max neval
         OP_solution() 7033.7550 7152.0689 7277.8248 7251.8419 7391.8664 7690.964   100
      map_str_detect() 2239.8715 2292.1271 2357.7432 2348.9975 2397.1758 2774.349   100
 unlist_lapply_fixed()  308.1492  331.9948  345.6262  339.9935  348.9907  586.169   100

Reduce_lapply胜利了!感谢@onyambu

Unit: milliseconds
                  expr       min        lq      mean    median        uq       max neval
       Reduce_lapply()  49.02941  53.61291  55.96418  55.31494  56.76109  80.64735   100
 unlist_lapply_fixed() 318.25518 335.58883 362.03831 346.71509 357.97142 566.95738   100

每个句子总是有三种颜色吗?你能改变“sentences”数据结构吗? - Tim Biegeleisen
@TimBiegeleisen,这个例子只是为了简单的说明。我正在搜索描述医学诊断的字符字符串,这些字符字符串超过73K,每个诊断都有一到两个描述句子。 - guasi
考虑对数据结构进行“归一化”处理,使得每种颜色出现在单独的一行中。 - Tim Biegeleisen
1
请检查我提供的Reduce答案。它比其他答案更快。我相信就速度而言,这是最快的,您应该考虑使用它。 - Onyambu
2个回答

3

编辑: 另一个选择是循环搜索模式,而不是遍历句子:

使用:

Reduce("&", lapply(search_terms, grepl, sentences, fixed = TRUE))
[1]  TRUE FALSE FALSE

基准测试

Unit: milliseconds
                  expr      min        lq      mean    median        uq       max neval
         OP_solution()  80.6365  81.61575  85.76427  83.20265  87.32975  163.0302   100
      map_str_detect() 546.4681 563.08570 596.26190 571.52185 603.03980 1383.7969   100
 unlist_lapply_fixed()  61.8119  67.49450  71.41485  69.56290  73.77240  104.8399   100
       Reduce_lapply()   3.0604   3.11205   3.406012   3.14535   3.43130   6.3526   100

请注意,这非常快!

旧文章:

使用以下方式使用 all 函数:

unlist(lapply(strsplit(sentences, " ", fixed = TRUE), \(x)all(search_terms %in% x)))

基准测试:

OP_solution <- function(){
   pattern <- paste0("(?=.*", search_terms,")", collapse="") 
   grepl(pattern, sentences, perl = TRUE)
}

map_str_detect <- function(){
    purrr::map_lgl(
      .x = sentences,
      .f = ~ all(stringr::str_detect(.x, search_terms))
    )
}

unlist_lapply_fixed <- function() unlist(lapply(strsplit(sentences, " ", fixed = TRUE), \(x)all(search_terms %in% x)))


sentences <- rep(sentences, 10000)
microbenchmark::microbenchmark( OP_solution(),map_str_detect(),
                   unlist_lapply_fixed(), check = 'equal')
Unit: milliseconds
                  expr      min        lq      mean    median        uq      max neval
         OP_solution()  80.5368  81.40265  85.14451  82.73985  86.41345 118.7052   100
      map_str_detect() 542.3555 553.84080 587.15748 566.66570 607.77130 782.5189   100
 unlist_lapply_fixed()  60.4955  66.94420  71.94195  69.30135  72.16735 113.6567   100

    

谢谢@onyambu。我已经使用了两个建议,现在我可以数到四个Mississippis!虽然你最后一个建议似乎更快。我正在搜索73K个观察结果,每个结果都有一两个句子。看起来不算多,但延迟是明显的。使用|运算符可以立即返回结果。 - guasi
@guasi 你使用 | 是什么意思? - Onyambu
OR运算符|。如果我搜索任何搜索词(blue)|(red),结果是立即的。如果我使用任何建议的方法搜索所有术语,则结果明显延迟。 - guasi
请注意,使用 | 无法获得所需的结果。这将搜索蓝色或红色,而不是同时搜索两者。请检查我发布的 Reduce 方法。 - Onyambu
谢谢你,@onyambu!你太棒了!Reduce_lapply方法真是快得惊人!这就是我要使用的方法。 - guasi

0

你可以尝试混合使用 purrrstringr 函数来解决:

library(tidyverse)

purrr::map_lgl(
  .x = sentences,
  .f = ~ all(stringr::str_detect(.x, search_terms))
)

同样的问题,执行时间很长。我正在寻找一个执行时间更短的解决方案。 - guasi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接