这篇文章的另一个潜在标题可能是"当在r中进行并行处理时,核心数,循环块大小和对象大小之间的比例是否重要?"
我有一个语料库我正在使用tm包运行一些转换。由于语料库很大,我使用并行处理多波并行包。
有时转换可以完成任务,但有时它们不会。例如,tm::removeNumbers()
。语料库中的第一个文档的内容值为" n417"。因此,如果预处理成功,那么此文档将转换为" n"。
下面的样本语料库用于复制。这是代码块:
library(tidyverse)
library(qdap)
library(stringr)
library(tm)
library(textstem)
library(stringi)
library(foreach)
library(doParallel)
library(SnowballC)
corpus <- (see below)
n <- 100 # this is the size of each chunk in the loop
# split the corpus into pieces for looping to get around memory issues with transformation
nr <- length(corpus)
pieces <- split(corpus, rep(1:ceiling(nr/n), each=n, length.out=nr))
lenp <- length(pieces)
rm(corpus) # save memory
# save pieces to rds files since not enough RAM
tmpfile <- tempfile()
for (i in seq_len(lenp)) {
saveRDS(pieces[[i]],
paste0(tmpfile, i, ".rds"))
}
rm(pieces) # save memory
# doparallel
registerDoParallel(cores = 12)
pieces <- foreach(i = seq_len(lenp)) %dopar% {
piece <- readRDS(paste0(tmpfile, i, ".rds"))
# regular transformations
piece <- tm_map(piece, content_transformer(removePunctuation), preserve_intra_word_dashes = T)
piece <- tm_map(piece, content_transformer(function(x, ...)
qdap::rm_stopwords(x, stopwords = tm::stopwords("english"), separate = F)))
piece <- tm_map(piece, removeNumbers)
saveRDS(piece, paste0(tmpfile, i, ".rds"))
return(1) # hack to get dopar to forget the piece to save memory since now saved to rds
}
stopImplicitCluster()
# combine the pieces back into one corpus
corpus <- list()
corpus <- foreach(i = seq_len(lenp)) %do% {
corpus[[i]] <- readRDS(paste0(tmpfile, i, ".rds"))
}
corpus_done <- do.call(function(...) c(..., recursive = TRUE), corpus)
here是示例数据的链接。我需要粘贴一个足够大的2k文档样本来重新创建,所以我不会粘贴那么多,所以请查看链接的doc数据。
corpus <- VCorpus(VectorSource([paste the chr vector from link above]))
如果我运行上面的代码块,n = 200,那么看一下结果
我可以看到数字仍然应该被tm::removeNumbers()
> lapply(1:10, function(i) print(corpus_done[[i]]$content)) %>% unlist
[1] "n417"
[1] "disturbance"
[1] "grand theft auto"
但是,如果我将块大小(&#34; n&#34;变量的值)更改为100:
> lapply(1:10, function(i) print(corpus_done[[i]]$content)) %>% unlist
[1] "n"
[1] "disturbance"
[1] "grand theft auto"
这些数字已被移除。
但是,这是不一致的。我试图通过测试150,然后125 ...来缩小它,并发现它将在120和125块大小之间/不会工作。然后在120:125之间迭代函数之后,它有时会工作,然后不是相同的块大小。
我想也许在3个变量之间存在这个问题的关系:语料库的大小,块大小和registerdoparallel()
中的核心数量。我只是不知道它是什么。
任何人都可以伸出援助之手,甚至可以使用链接的样本语料库进行复制吗?我担心,因为我有时可以重现错误,有时我不能。更改块大小可以通过删除数字来查看错误,但并非总是如此。
更新 今天我恢复了我的会话,无法复制错误。我创建了一个Google Doc并尝试了不同的语料库大小,核心数量和块大小的值。在每种情况下,一切都是成功的。所以,我尝试运行完整数据,一切正常。但是,为了我的理智,我尝试在完整数据上再次运行,但它失败了。现在,我回到了昨天的位置。 似乎已经在更大的数据集上运行功能已经改变了一些东西......我不知道是什么。也许某种会话变量? 因此,新信息是只有在非常大的数据集上运行函数后才会出现此错误。重新启动我的会话并没有解决问题,但是在离开几个小时之后恢复会话。
新信息。在较大的语料库上重现问题可能更容易,因为这似乎触发了问题corpus <- do.call(c, replicate(250, corpus, simplify = F))
将根据我提供的示例创建500k文档语料库。该功能可能在您第一次调用它时起作用,但对我来说,它似乎第二次失败。
这个问题很难,因为如果我可以重现这个问题,我很可能会识别并修复它。
新信息。因为这个函数发生了很多事情,所以很难知道在哪里集中调试工作。我正在研究我使用多个临时RDS文件来节省内存的事实,以及我正在进行并行处理的事实。我写了两个替代版本的脚本,一个仍然使用rds文件并打破语料库但没有进行并行处理(用%do%替换%dopar%并且还删除了registerDoParallel行)和一个使用并行处理但是不使用RDS临时文件来分割小样本语料库。我无法使用单核心版本的脚本生成错误,只有使用%dopar%的版本才能重新创建问题(虽然问题是间歇性的,但并不总是会失败,因为多巴)。
因此,只有在使用%dopar%
时才会出现此问题。我使用临时RDS文件的事实似乎不是问题的一部分。