有效地替换 text2vec 中的单词

Replace words in text2vec efficiently

我有一个很大的正文,我想用它们各自的同义词有效地替换单词(例如用同义词 "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,但我不确定如何使用。有什么想法吗?

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

很晚了,但我还是想加我的 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. 自然这个任务是为了hash-table查找。据我所知,最快的实现是在 fastmatch 包中。所以你可以编写自定义分词器,比如:

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

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

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"