以块为单位读取大型文本文件



我正在使用有限的RAM(AWS免费套餐EC2服务器 - 1GB(。

我有一个相对较大的 txt 文件"vectors.txt"(800mb(,我正在尝试读取 R。尝试了各种方法后,我都无法在此向量中读取内存。

所以,我正在研究分块阅读它的方法。我知道结果数据框的亮度应该是 300K * 300。如果我能够一次读取文件(例如 10K 行(,然后将每个块另存为 RDS 文件,我将能够遍历结果并获得我需要的东西,尽管只是慢一点,比将整个东西放在内存中更不方便。

要重现:

# Get data
url <- 'https://github.com/eyaler/word2vec-slim/blob/master/GoogleNews-vectors-negative300-SLIM.bin.gz?raw=true'
file <- "GoogleNews-vectors-negative300-SLIM.bin.gz"
download.file(url, file) # takes a few minutes
R.utils::gunzip(file)
# word2vec r library
library(rword2vec)
w2v_gnews <- "GoogleNews-vectors-negative300-SLIM.bin"
bin_to_txt(w2v_gnews,"vector.txt")

目前为止,一切都好。这是我挣扎的地方:

word_vectors = as.data.frame(read.table("vector.txt",skip = 1, nrows = 10))

返回"无法分配大小 [size] 的向量"错误消息。

尝试过的替代方案:

word_vectors <- ff::read.table.ffdf(file = "vector.txt", header = TRUE)

相同,内存不足

word_vectors <- readr::read_tsv_chunked("vector.txt", 
callback = function(x, i) saveRDS(x, i),
chunk_size = 10000)

结果是:

Parsed with column specification:
cols(
`299567 300` = col_character()
)
|=========================================================================================| 100%  817 MB
Error in read_tokens_chunked_(data, callback, chunk_size, tokenizer, col_specs,  : 
Evaluation error: bad 'file' argument.

有没有其他方法可以将向量.txt转换为数据框?也许通过将其分解成碎片并读取每部分,保存为数据框,然后保存到 rds?还是其他选择?

编辑: 从乔纳森下面的回答中,尝试过:

library(rword2vec)
library(RSQLite)
# Download pre trained Google News word2vec model (Slimmed down version)
# https://github.com/eyaler/word2vec-slim
url <- 'https://github.com/eyaler/word2vec-slim/blob/master/GoogleNews-vectors-negative300-SLIM.bin.gz?raw=true'
file <- "GoogleNews-vectors-negative300-SLIM.bin.gz"
download.file(url, file) # takes a few minutes
R.utils::gunzip(file)
w2v_gnews <- "GoogleNews-vectors-negative300-SLIM.bin"
bin_to_txt(w2v_gnews,"vector.txt")

# from https://privefl.github.io/bigreadr/articles/csv2sqlite.html
csv2sqlite <- function(tsv,
every_nlines,
table_name,
dbname = sub("\.txt$", ".sqlite", tsv),
...) {
# Prepare reading
con <- RSQLite::dbConnect(RSQLite::SQLite(), dbname)
init <- TRUE
fill_sqlite <- function(df) {
if (init) {
RSQLite::dbCreateTable(con, table_name, df)
init <<- FALSE
}
RSQLite::dbAppendTable(con, table_name, df)
NULL
}
# Read and fill by parts
bigreadr::big_fread1(tsv, every_nlines,
.transform = fill_sqlite,
.combine = unlist,
... = ...)
# Returns
con
}
vectors_data <- csv2sqlite("vector.txt", every_nlines = 1e6, table_name = "vectors")

结果是:

Splitting: 12.4 seconds.
Error: nThread >= 1L is not TRUE

另一种选择是在磁盘上进行处理,例如使用SQLite文件和dplyr的数据库功能。这是一个选项:https://stackoverflow.com/a/38651229/4168169

要将CSV放入SQLite,您还可以使用bigreadr包,其中包含有关执行此操作的文章:https://privefl.github.io/bigreadr/articles/csv2sqlite.html

最新更新