分块读取大文本文件

Posted

技术标签:

【中文标题】分块读取大文本文件【英文标题】:Read in large text file in chunks 【发布时间】:2019-03-12 11:54:45 【问题描述】:

我正在使用有限的 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.

还有其他方法可以将vectors.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

【问题讨论】:

【参考方案1】:

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

要将 CSV 导入 SQLite,您还可以使用 bigreadr 包,其中有一篇关于这样做的文章:https://privefl.github.io/bigreadr/articles/csv2sqlite.html

【讨论】:

感谢您的建议。这里的问题是,在查看 SQLite 之后,我需要在将数据添加到表之前创建一个具有正确字段名称的表。由于我什至无法读取文件的一部分,我只是猜测有多少字段 您可以将文件的一小块读入 R 并从中创建(空)SQLite 表(通过 RSQLite),然后用完整数据更新它。这几乎就是 bigreadr 所做的......我会更新我的答案。 嗨@Jonathan,我尝试按照链接中的示例操作,结果为Splitting: 12.4 seconds. Error: nThread &gt;= 1L is not TRUE 。如果您从我的编辑下方粘贴整个代码块,您应该(希望)能够复制。不过,使用download.file(url, file) 行下载文件需要几分钟时间。我觉得我很接近了。我怀疑可能是 txt 文件的格式(示例使用 csv)。

以上是关于分块读取大文本文件的主要内容,如果未能解决你的问题,请参考以下文章

python大文件处理

Python:分块读取大文件

Python:分块读取大文件

C#读取大文本文件

如何提高java读取大文本文件的效率

如何在 Swing 中读取和显示大文本文件?