寻找一种优化的方式来替换长文档中的列表模式

Looking for an optimized way of replacing list patterns in long documents

使用 tm 包,我有一个包含 10,900 个文档的语料库 (docs)。

docs = Corpus(VectorSource(abstracts$abstract))

我还有一个术语列表 (termslist) 及其所有同义词和不同的拼写。我用它来将每个同义词或拼写转换为一个术语。

Term, Synonyms
term1, synonym1
term1, synonym2
term1, synonym3
term2, synonym1
... etc

我现在的做法是遍历所有文档,另一个嵌套者循环遍历所有术语以查找和替换。

for (s in 1:length(docs)){
  for (i in 1:nrow(termslist)){
    docs[[s]]$content<-gsub(termslist[i,2], termslist[i,1], docs[[s]])
  }
  print(s)
}

目前,对于一个文档(在 termslist 中有大约 1000 行),这需要一秒钟,这意味着 10,900 秒,大约 6 小时!

在 tm 包或 R 中一般有更优化的方法吗?

更新:

mathematical.coffee的回答实际上很有帮助。我不得不重新创建一个 table 行,第二列是用 '|' 分隔的同义词,然后循环遍历它们。现在花费的时间比以前少了很多。

**[乱七八糟]创建新代码table:

newtermslist<-list()
authname<-unique(termslist[,1])
newtermslist<- cbind(newtermslist,authname)
syns<-list()
for (i in seq(authname)){
  syns<- rbind(syns,
                   paste0('(', 
                          paste(termslist[which(termslist[,1]==authname[i]),2],collapse='|')
                          , ')')
  )
}
newtermslist<-cbind(newtermslist,syns)
newtermslist<-cbind(unlist(newtermslist[,1]),unlist(newtermslist[,2]))

我认为当你希望执行多次替换时,这可能是唯一的方法(即顺序地,将替换的输出保存为下一次替换的输入)。

但是,您可能会尝试获得一些速度(您必须进行一些基准测试才能进行比较):

  • 使用 fixed=T(因为您的同义词不是正则表达式而是字面拼写),useBytes=T(**请参阅 ?gsub - 如果您有多字节语言环境,这可能是也可能不是好主意)。或者
  • 压缩您的术语列表 - 如果 blue 有同义词 ceruleancobaltsky,那么您的正则表达式可能是 (cerulean|cobalt|sky) 替换 blue,这样 blue 的所有同义词都在一次迭代中被替换,而不是在 3 个单独的迭代中被替换。为此,您需要预处理您的术语列表 - 例如newtermslist <- ddply(terms, .(term), summarize, regex=paste0('(', paste(synonym, collapse='|'), ')')) 然后执行当前循环。您将拥有 fixed=F(默认值,即使用正则表达式)。
  • 另请参阅 ?tm_map?content_transformer。我不确定这些是否会加快速度,但您可以试试。

(重新基准测试 - 尝试 library(rbenchmark); benchmark(expression1, expression2, ...),或者好的 ol' system.time 用于计时,Rprof 用于分析)

我在这里回答了我自己的问题,这是在通过一个可以并行处理事情的并行化解决方案之后得出的。它应该 运行 代码更快,但我还没有比较这两个解决方案。

library(doParallel)
library(foreach)
cl<-makeCluster(detectCores())
registerDoParallel(cl)
system.time({ # this one to print how long it takes after it evaluate the expression
  foreach(s=1:length(docs)) %:% foreach(i=1:nrow(newtermslist)) %dopar% {
    docs[[s]]$content<-gsub(newtermslist[i,2], newtermslist[i,1], docs[[s]]$content)
  }
})
stopCluster(cl)