使udpipe_annotate()更快

4
我是一名有用的助手,能够翻译文本。

我目前正在进行文本挖掘文档的工作,希望从我的文本中提取相关关键字(请注意,我有很多文本文档)。

我正在使用udpipe包。一个很棒的指南可以在http://bnosac.be/index.php/blog/77-an-overview-of-keyword-extraction-techniques上找到。一切都正常,但当我运行代码时,出现了这部分

x <- udpipe_annotate(ud_model, x = comments$feedback)

当你有大量文本时,速度非常慢。 是否有人有想法如何更快地完成这一部分?当然,解决方法也可以。

library(udpipe)
library(textrank)
## First step: Take the Spanish udpipe model and annotate the text. Note: this takes about 3 minutes

data(brussels_reviews)
comments <- subset(brussels_reviews, language %in% "es")
ud_model <- udpipe_download_model(language = "spanish")
ud_model <- udpipe_load_model(ud_model$file_model)
x <- udpipe_annotate(ud_model, x = comments$feedback) # This part is really, really slow 
x <- as.data.frame(x)

非常感谢提前!

3个回答

6

我根据未来的API添加了一个答案。这适用于您使用的任何操作系统(Windows、Mac或Linux)。

future.apply包提供了基本*apply系列的所有并行替代方案。其余代码基于@jwijffels的答案。唯一的区别是我在annotate_splits函数中使用了data.table。

library(udpipe)
library(data.table)

data(brussels_reviews)
comments <- subset(brussels_reviews, language %in% "es")
ud_model <- udpipe_download_model(language = "spanish", overwrite = F)
ud_es <- udpipe_load_model(ud_model)


# returns a data.table
annotate_splits <- function(x, file) {
  ud_model <- udpipe_load_model(file)
  x <- as.data.table(udpipe_annotate(ud_model, 
                                     x = x$feedback,
                                     doc_id = x$id))
  return(x)
}


# load parallel library future.apply
library(future.apply)

# Define cores to be used
ncores <- 3L
plan(multiprocess, workers = ncores)

# split comments based on available cores
corpus_splitted <- split(comments, seq(1, nrow(comments), by = 100))

annotation <- future_lapply(corpus_splitted, annotate_splits, file = ud_model$file_model)
annotation <- rbindlist(annotation)

这正是我正在寻找的。太棒了!!非常感谢。 - R overflow

2
R包udpipe使用UDPipe 1.2 C++库。注释速度详见论文(参见https://doi.org/10.18653/v1/K17-3009的表8)。如果您想加快速度,可以将其并行运行,因为注释是可以轻松并行化的。
以下示例通过parallel::mclapply在16个核心上并行运行,如果您有16个核心,则可获得16倍的速度提升,适用于大型语料库。您可以使用任何并行化框架,下面我使用了parallel包 - 如果您在Windows上,您需要使用例如parallel::parLapply,但没有任何限制阻止您使用其他并行选项(snow / multicore / future / foreach /...)来进行并行注释。
library(udpipe)
library(data.table)
library(parallel)
data(brussels_reviews)
comments <- subset(brussels_reviews, language %in% "fr")
ud_model <- udpipe_download_model(language = "french-partut")

annotate_splits <- function(x, file) {
  model <- udpipe_load_model(file)
  x <- udpipe_annotate(model, x = x$feedback, doc_id = x$id, tagger = "default", parser = "default")
  as.data.frame(x, detailed = TRUE)
}

corpus_splitted <- split(comments, seq(1, nrow(comments), by = 100))
annotation <- mclapply(corpus_splitted, FUN = function(x, file){
  annotate_splits(x, file) 
}, file = ud_model$file_model, mc.cores = 16)
annotation <- rbindlist(annotation)

请注意,udpipe_load_model也需要一些时间,因此最好的策略可能是在您机器上拥有的核心数量上并行化它,而不是像我上面展示的那样分成100块。

谢谢!对于udpipe_load_model,它使用以下语句(以便只下载一次):ifelse(file.exists('english-ud-2.0-170801.udpipe'), ud_model <- udpipe_load_model(file = 'english-ud-2.0-170801.udpipe'), ud_model <- udpipe_download_model(language = "english"))非常感谢您的努力! - R overflow
你能否给我一个Windows的例子?我尝试使用parLapply运行上面的例子,但这对我来说真的很新...所以我一直收到错误。 - R overflow
在StackOverflow上发布一个关于使用parallel包的问题,展示你所做的代码,并希望其他熟悉并行框架的人能够帮助你解决问题。 - user1600826

0

您还可以使用furrrfuture库来完成此操作,这样做的好处是有一个进度条。

我对另外两个答案中的udpipe_load_model实现有些困惑。您可以先在函数外部加载模型一次,这样函数每次运行时就不必再加载模型了。

library(udpipe)
library(future)
library(furrr)
data(brussels_reviews)

comments <- subset(brussels_reviews, language %in% "es")
downloaded_model <- udpipe_download_model(language = "spanish", overwrite = FALSE)
model <- udpipe_load_model(downloaded_model)

annotate_splits <- function(text) {
  anno <- udpipe_annotate(model, x = text$feedback, doc_id = text$id, tagger = "default", parser = "default")
  x <- as.data.frame(anno, detailed = TRUE)
  return(x)
}

split_corpus <- split(comments, seq(1, nrow(comments), by = 100))

#recommend setting workers equal to number of your computer's cores
plan(multisession, workers = 2) 
dfs <- future_map(split_corpus, annotate_splits, .progress = TRUE)

annotated_df <- dplyr::bind_rows(dfs)

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