【问题标题】:Replace words in text2vec efficiently有效地替换 text2vec 中的单词
【发布时间】:2017-01-11 09:33:00
【问题描述】:

我有一个大文本正文,我想有效地用它们各自的同义词替换单词(例如用同义词“car”替换所有出现的“automobile”)。但我很难找到一种合适的(有效的方法)来做到这一点。

为了以后的分析,我使用了text2vec 库,并且也希望将该库用于此任务(避免tm 以减少依赖关系)。

一种(低效的)方式如下所示:

# setup data
text <- c("my automobile is quite nice", "I like my car")

syns <- list(
  list(term = "happy_emotion", syns = c("nice", "like")),
  list(term = "car", syns = c("automobile"))
)

我的蛮力解决方案是有这样的东西并使用循环来查找单词并替换它们

library(stringr)
# works but is probably not the best...
text_res <- text
for (syn in syns) {
  regex <- paste(syn$syns, collapse = "|")
  text_res <-  str_replace_all(text_res, pattern = regex, replacement = syn$term)
}
# which gives me what I want
text_res
# [1] "my car is quite happy_emotion" "I happy_emotion my car" 

我曾经使用tm 使用这种方法by MrFlick(使用tm::content_transformertm::tm_map)来完成它,但我想通过将tm 替换为更快的text2vec 来减少项目的依赖关系.

我想最佳解决方案是以某种方式使用text2vecs itoken,但我不确定如何使用。有什么想法吗?

【问题讨论】:

    标签: r text2vec


    【解决方案1】:

    很晚了,但我还是想加我的 2 美分。 我看到了 2 个解决方案

    1. 对您的 str_replace_all 的小改进。由于它是内部矢量化的,因此您可以在没有循环的情况下进行所有替换。我认为它会更快,但我没有做任何基准测试。

      regex_batch = sapply(syns, function(syn) paste(syn$syns, collapse = "|"))  
      names(regex_batch) = sapply(syns, function(x) x$term)  
      str_replace_all(text, regex_batch)  
      
    2. 这个任务自然是用于哈希表查找。据我所知,最快的实现是在fastmatchpackage。因此,您可以编写自定义标记器,例如:

      library(fastmatch)
      
      syn_1 = c("nice", "like")
      names(syn_1) = rep('happy_emotion', length(syn_1))
      syn_2 = c("automobile")
      names(syn_2) = rep('car', length(syn_2))
      
      syn_replace_table = c(syn_1, syn_2)
      
      custom_tokenizer = function(text) {
        word_tokenizer(text) %>% lapply(function(x) {
          i = fmatch(x, syn_replace_table)
          ind = !is.na(i)
          i = na.omit(i)
          x[ind] = names(syn_replace_table)[i]
          x
        })
      }
      

    我敢打赌,第二种解决方案会更快,但需要进行一些基准测试。

    【讨论】:

    • 这看起来是一个非常有趣的概念!我对它们做了一些快速的基准测试。在小的同义词样本上,for 循环更快,fastmatch 方法在更大的列表上要快得多!另外,由于我还在做这个项目,你的 2 美分在这里非常有价值!
    • 另请注意,text2vec::word_tokenizerstringr::str_split(TEXT_HERE, pattern = stringr::boundary("word")) 相比相当慢。我不使用stringr/stringi/tokenizers 的唯一原因是我希望尽可能少地使用text2vec 依赖项。
    【解决方案2】:

    使用 base R 这应该可以工作:

    mgsub <- function(pattern,replacement,x) {
    if (length(pattern) != length(replacement)){
        stop("Pattern not equal to Replacment")
    } 
        for (v in 1:length(pattern)) {
            x  <- gsub(pattern[v],replacement[v],x)
        }
    return(x )
    }
    
    mgsub(c("nice","like","automobile"),c(rep("happy_emotion",2),"car"),text)
    

    【讨论】:

    • 这不是和我贴的循环很像吗?只是用gsub替换stringr::str_replace_all
    • 是的,但是因为你想减少依赖,我想你想要一个基本的 R 解决方案。你检查过this 吗?
    • 我知道perl = T(确实增加了速度),而且它似乎比stringr 快。但是,我仍然想知道text2vec 是否提供了更快的替代方案(通过使用令牌...)
    【解决方案3】:

    Dmitriy Selivanov 解决方案的第一部分需要稍作改动。

    library(stringr)    
    
    text <- c("my automobile is quite nice", "I like my car")
    
    syns <- list(
                 list(term = "happy_emotion", syns = c("nice", "like")),
                 list(term = "car", syns = c("automobile"))
                 )
    
    regex_batch <- sapply(syns, function(syn) syn$term)  
    names(regex_batch) <- sapply(syns, function(x) paste(x$syns, collapse = "|"))  
    text_res <- str_replace_all(text, regex_batch) 
    
    text_res
    [1] "my car is quite happy_emotion" "I happy_emotion my car"  
    

    【讨论】:

      猜你喜欢
      • 2020-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 2015-03-02
      • 2013-03-20
      相关资源
      最近更新 更多