Читать огромный CSV-файл, используя `read.csv` по стратегии «разделяй и властвуй»?

Я должен прочитать большой CSV-файл (5,4 ГБ с 7 млн ​​строк и 205 столбцов) в R. Я успешно прочитал его, используя data.table::fread(). Но я хочу знать, можно ли прочитать это, используя базовый read.csv()?

Я пытался просто использовать грубую силу, но моя 16 ГБ ОЗУ не может этого выдержать. Затем я попытался использовать стратегию «разделяй и властвуй» (дробление), как показано ниже, но это все равно не сработало. Как мне это сделать?

dt1 <- read.csv('./ss13hus.csv', header = FALSE, nrows = 721900, skip =1)
print(paste(1, 'th chunk completed'))
system.time(
  for (i in (1:9)){
    tmp = read.csv('./ss13hus.csv', header = FALSE, nrows = 721900, skip = i * 721900 + 1)
    dt1 <- rbind(dt1, tmp)
    print(paste(i + 1, 'th chunk completed'))
  }
)

Также я хочу знать, как работает fread(), который может считывать все данные сразу и очень эффективно, независимо от памяти или времени?


person Hengcheng Zhu    schedule 14.04.2019    source источник
comment
Я не думаю, что проблема в загрузке данных, я думаю, проблема в хранении данных. Не говоря уже о том, что итеративная сборка с rbind — это всегда плохо: каждый раз, когда она добавляет что-нибудь, R делает полную копию предыдущих данных. Для предыдущих сборок я предпочитаю do.call(rbind.data.frame, lapply(fnames, read.csv)), но я не уверен, что это решит вашу проблему с большими данными. Если это не сработает, вы можете рассмотреть возможность обработки только части данных за раз, агрегировать их (?), сохранить и перейти к следующему пакету.   -  person r2evans    schedule 15.04.2019
comment
Да, это называется чтение кусками. Однако ваша проблема связана с раздуванием памяти, вызванным тем, что вы не определили colClasses для ваших 205 столбцов (вам действительно нужно читать их все? Это будет очень тесно)   -  person smci    schedule 15.04.2019
comment
Да, мне нужно прочитать все данные. Но как я могу избавиться от проблемы с памятью?   -  person Hengcheng Zhu    schedule 15.04.2019
comment
Определите colClasses для ваших 205 столбцов, целые числа для целых столбцов, числовые значения для двойных столбцов, факторы для столбцов факторов. В противном случае вещи хранятся очень неэффективно. См. ?fread и руководство.   -  person smci    schedule 15.04.2019


Ответы (1)


Ваша проблема не fread(), это раздувание памяти, вызванное тем, что не определены colClasses для всех ваших (205) столбцов. Но имейте в виду, что попытка прочитать все 5,4 ГБ в 16 ГБ ОЗУ, в первую очередь, напрягает, вы почти наверняка не сможете хранить весь этот набор данных в памяти; и даже если бы вы могли, вы будете сбрасывать память всякий раз, когда пытаетесь ее обработать. Таким образом, ваш подход не сработает, вам нужно серьезно решить, с каким подмножеством вы можете работать, какие поля вам абсолютно необходимы для начала работы:

  • Определите colClasses для ваших 205 столбцов: "integer" для целочисленных столбцов, "numeric" для двойных столбцов, "logical" для логических столбцов, "factor" для столбцов-факторов. В противном случае вещи хранятся очень неэффективно (например, миллионы строк очень расточительны), и результат может легко быть в 5-100 раз больше, чем необработанный файл.

  • Если вы не можете уместить все 7 млн строк x 205 столбцов (что почти наверняка не удастся), то вам придется агрессивно сократить объем памяти, выполнив некоторые или все из следующих действий:

    • read in and process chunks (of rows) (use skip, nrows arguments, and search SO for questions on fread in chunks)
    • отфильтровать все ненужные строки (например, вы можете выполнить некоторую грубую обработку, чтобы сформировать индекс строки из подмножества строк, которые вам нужны, и позже импортировать этот гораздо меньший набор)
    • удалить все ненужные столбцы (используйте аргументы fread select/drop (укажите векторы имен столбцов, которые нужно сохранить или удалить).
  • Убедитесь, что опция stringsAsFactors=FALSE — это заведомо плохой вариант по умолчанию в R, который вызывает бесконечные проблемы с памятью.

  • Поля даты/даты-времени в настоящее время читаются как символы (что плохо для использования памяти, миллионы уникальных строк). Либо полностью удалите столбцы даты для начала, либо прочитайте данные по частям и преобразуйте их с помощью пакета fasttime или стандартных базовых функций.
  • Посмотрите на аргументы для обработки NA. На данный момент вы можете отказаться от столбцов с большим количеством NA или беспорядочных необработанных строковых полей.

См. ?fread и data.table документ для синтаксис вышеперечисленного. Если вы столкнулись с конкретной ошибкой, опубликуйте фрагмент, скажем, 2 строки данных (head(data)), ваш код и ошибку.

person smci    schedule 15.04.2019
comment
Спасибо за ваш ответ! Но, похоже, вы неправильно поняли мой вопрос. Я уже успешно загрузил этот файл размером 5,4 ГБ с помощью fread () (и свободной памяти стало больше более чем на 30%), но не работает для функции R baisc. 'read.csv' - person Hengcheng Zhu; 15.04.2019
comment
Меня сейчас удивляет, возможно ли просто использовать базовый read.csv() для загрузки всех данных? Все должно быть в порядке, верно? Потому что функция fread() уже успешно загружена. - person Hengcheng Zhu; 15.04.2019
comment
Вы также можете написать код вокруг read.csv() для чтения файлов по частям (используйте параметры nrows, skip). read.csv также принимает аргумент colClasses, что помогает сократить использование памяти. Я думаю, учитывая, что fread() работает, вам просто интересно отладить, почему read.csv задыхается. Попробуйте read.csv(..., nrows=1000), а затем посмотрите, какие столбцы сокращают использование вашей памяти. Но, честно говоря, базовый read.csv(), как известно, плохо работает с большими файлами, поэтому я бы не тратил на него много времени, это единственная причина, по которой пользователи написали пакеты data.table::fread() и readr, которые намного лучше. - person smci; 15.04.2019
comment
@HengchengZhu: я не вижу особого смысла исследовать, почему производительность read.csv такая ужасная (время выполнения и память). Почти все советы, которые я вам дал, справедливы и для read.csv. Если вы хотите, вы можете копаться в нем и опубликовать свои выводы. Известно, что read.csv имеет ужасную производительность, поэтому люди написали лучшие реализации data.table::fread(), readr пакета и т. д. - person smci; 19.04.2019