寻找在长文档中替换列表模式的优化方法

时间:2015-07-25 00:29:00

标签: r text-mining tm

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

docs = Corpus(VectorSource(abstracts$abstract))

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

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

我现在正在这样做的方法是循环遍历所有文档,另一个nester遍历所有术语以查找和替换。

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内执行此操作?

更新:

math.coffee的回答实际上很有帮助。我不得不重新创建一个具有唯一术语作为行的表,第二列将是由'|'分隔的同义词,然后只是循环它们。现在它的时间比以前少得多。

** [乱码]创建新表的代码:

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

2 个答案:

答案 0 :(得分:1)

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

但是,你可能会尝试一些速度(你必须做一些基准测试来比较):

  • 使用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}&{39;} system.time作为时间安排,Rprof进行性能分析

答案 1 :(得分:1)

在我通过并行解决方案并行处理之后,我回答了我自己的问题。它应该更快地运行代码,但我还没有比较这两个解决方案。

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)