Читать в большом текстовом файле кусками - PullRequest
0 голосов
/ 07 октября 2018

Я работаю с ограниченной оперативной памятью (бесплатный сервер EC2 уровня AWS - 1 ГБ).

У меня относительно большой текстовый файл "vectors.txt" (800 МБ), который я пытаюсь прочитать в R.Перепробовав различные методы, я не смог прочитать этот вектор в памяти.

Итак, я исследовал способы чтения его кусками.Я знаю, что размер результирующего фрейма данных должен составлять 300 К * 300. Если бы мне удалось прочитать в файле, например, по 10 Кбайт за раз, а затем сохранить каждый фрагмент в виде файла 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))

Возвращает сообщение об ошибке «невозможно выделить вектор размера [размера]».

Пробные альтернативы:

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 Ответ

0 голосов
/ 08 октября 2018

Другим вариантом будет выполнение обработки на диске, например, с использованием файла SQLite и функциональности базы данных dplyr.Вот один из вариантов: https://stackoverflow.com/a/38651229/4168169

Чтобы получить CSV-файл в SQLite, вы также можете использовать пакет bigreadr, в котором есть статья о том, как это сделать: https://privefl.github.io/bigreadr/articles/csv2sqlite.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...