我有一個很大的語料庫,我正在與tm::tm_map()
進行轉換。由於我使用託管的R Studio,因此我有15個內核,並希望利用並行處理來加快速度。多邊並行嵌套在循環中的循環工作,但邏輯上沒有意義?
沒有共享一個非常大的語料庫,我簡直無法用虛擬數據重現。
我的代碼如下。對問題的簡短描述是在控制檯中手動循環切片,但在我的函數內部不這樣做。
函數「clean_corpus」將語料庫作爲輸入,將其分解成片段並保存到臨時文件以幫助解決內存問題。然後該函數使用%dopar
%塊對每個片段進行迭代。該功能在對語料庫的一小部分進行測試時起作用,例如10K文件。但是在較大的語料庫上,函數返回NULL。爲了調試,我設置了函數來返回已經循環的單個片段,而不是整個重建的語料庫。我發現在較小的語料庫樣本中,代碼會按預期返回所有迷你語料庫的列表,但是當我在語料庫的較大樣本上進行測試時,該函數將返回一些空值。
這裏的原因,這是莫名其妙對我說:
cleaned.corpus <- clean_corpus(corpus.regular[1:10000], n = 1000) # works
cleaned.corpus <- clean_corpus(corpus.regular[10001:20000], n = 1000) # also works
cleaned.corpus <- clean_corpus(corpus.regular[1:50000], n = 1000) # NULL
如果我這樣做是10K塊高達例如50k通過5次迭代一切正常。如果我在例如完整的50k文件它返回NULL。
所以,也許我只是需要循環更多的小碎片通過打破我的語料庫。我試過這個。在下面的clean_corpus函數中,參數n是每件的長度。該函數仍然返回NULL。
所以,如果我重複這樣的:
# iterate over 10k docs in 10 chunks of one thousand at a time
cleaned.corpus <- clean_corpus(corpus.regular[1:10000], n = 1000)
如果我這樣做,手動5次高達50K一切正常。通過我的函數在一次調用中這樣做的等價物是:
# iterate over 50K docs in 50 chunks of one thousand at a time
cleaned.corpus <- clean_corpus(corpus.regular[1:50000], n = 1000)
返回NULL。
This SO帖子和唯一答案中的鏈接提示可能與我在linux上的RStudio託管實例有關,因爲linux「內存不足的兇手」可能會阻止工作人員。這就是爲什麼我試圖將我的語料庫分解成碎片,以解決內存問題。
任何關於爲什麼在10k大小的1k中迭代10k文檔的任何理論或建議都適用,而50k大小的1k不適用?
這裏的clean_corpus功能:從上面再次
clean_corpus <- function(corpus, n = 500000) { # n is length of each peice in parallel processing
# 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 = 14) # I've experimented with 2:14 cores
pieces <- foreach(i = seq_len(lenp)) %dopar% {
piece <- readRDS(paste0(tmpfile, i, ".rds"))
# transformations
piece <- tm_map(piece, content_transformer(replace_abbreviation))
piece <- tm_map(piece, content_transformer(removeNumbers))
piece <- tm_map(piece, content_transformer(function(x, ...)
qdap::rm_stopwords(x, stopwords = tm::stopwords("en"), separate = F, strip = T, char.keep = c("-", ":", "/"))))
}
# combine the pieces back into one corpus
corpus <- do.call(function(...) c(..., recursive = TRUE), pieces)
return(corpus)
} # end clean_corpus function
代碼塊只是打字功能之後可讀性的流程:
# iterate over 10k docs in 10 chunks of one thousand at a time
cleaned.corpus <- clean_corpus(corpus.regular[1:10000], n = 1000) # works
# iterate over 50K docs in 50 chunks of one thousand at a time
cleaned.corpus <- clean_corpus(corpus.regular[1:50000], n = 1000) # does not work
但在控制檯迭代通過調用每個
功能corpus.regular[1:10000], corpus.regular[10001:20000], corpus.regular[20001:30000], corpus.regular[30001:40000], corpus.regular[40001:50000] # does work on each run
注意我嘗試使用庫tm功能進行並行處理(請參見here),但我一直在打「無法分配內存」錯誤,這就是爲什麼我試圖使用doparallel %dopar%
「自己做」的原因。
嗨,感謝您的評論。我知道這是一個記憶問題..但這正是我去循環路線的原因。循環是否有助於通過大塊計算而不是整體計算來緩解這種情況? –
此外,我確實看着他的腳本運行1 +核心通過殼>頂部> 1.在每種情況下似乎都失去了免費的內存。 –
啊,我從來沒有考慮過這個。事情是我能夠將整個結構加載到R.50k樣本對於整個10M文檔語料庫是很小的,所以即使是塊也不應該導致內存問題。我想知道我是否應該嘗試將所有片斷保存到臨時文件中,就像我在功能的頂部附近做的那樣 –