Подтвердить что ты не робот

Стратегии для чтения в CSV файлах?

У меня есть файл с умеренным размером (4 ГБ CSV) на компьютере, на котором нет достаточного количества ОЗУ для чтения (8 ГБ в 64-битной Windows). Раньше я просто загружал его в кластер node и читал его, но мой новый кластер, по-видимому, произвольно ограничивал процессы до 4 ГБ ОЗУ (несмотря на аппаратное обеспечение, имеющее 16 ГБ на машину), поэтому мне нужен коротко- долгосрочное исправление.

Есть ли способ прочитать часть CSV файла в R, чтобы соответствовать ограничениям доступной памяти? Таким образом, я мог бы читать в третьем файле за раз, подмножить его на строки и столбцы, которые мне нужны, а затем читать в следующей трети?

Спасибо комментаторам за то, что я могу потенциально читать во всем файле, используя некоторые трюки с большой памятью: Быстрое чтение очень больших таблиц в качестве данных в R

Я могу думать о некоторых других обходных решениях (например, открывать в хорошем текстовом редакторе, отрывать 2/3 наблюдений, затем загружать в R), но я предпочел бы избежать их, если это возможно.

Так что чтение его на куски по-прежнему кажется лучшим вариантом.

4b9b3361

Ответ 1

Вы можете прочитать его в базе данных, используя RSQLite, скажем, и затем использовать оператор sql для получения части.

Если вам нужна только одна часть, то read.csv.sql в пакете sqldf будет считывать данные в базу данных sqlite. Он создает базу данных для вас, и данные не проходят через R, поэтому ограничения R не будут применяться. После прочтения его в базе данных он считывает вывод указанного оператора sql в R и затем уничтожает базу данных. В зависимости от того, насколько быстро он работает с вашими данными, вы можете просто повторить весь процесс для каждой части, если у вас их несколько.

Так как его единственная строка кода, чтобы сделать все это для одной части, это просто, просто попробуйте. DF <- read.csv.sql("myfile.csv", sql=..., ...other args...). См. ?read.csv.sql и ?sqldf, а также домашняя страница sqldf.

Ответ 2

Я знаю, что это очень старый поток. Однако я встретил это недавно, потому что у меня была аналогичная проблема. После чрезмерного просмотра этой темы я заметил, что заметное решение этой проблемы не упоминалось. Использовать соединения!

1) Откройте соединение с файлом

con = file("file.csv", "r")

2) Читайте в кусках кода с read.csv

read.csv(con, nrows="CHUNK SIZE",...)

Боковое примечание: определение colClasses значительно ускорит процесс. Обязательно определите нежелательные столбцы как NULL.

3) Сделайте то, что вам нужно сделать

4) Повторите.

5) Закройте соединение

close(con)

Преимущество такого подхода - это соединения. Если вы опустите этот шаг, это, скорее всего, немного замедлит работу. Открыв соединение вручную, вы по существу открываете набор данных и не закрываете его, пока не назовете функцию закрытия. Это означает, что при прохождении через набор данных вы никогда не потеряете свое место. Представьте, что у вас есть набор данных с 1e7 строками. Также представьте, что вы хотите загрузить кусок из 1 строки по одному за раз. Поскольку мы открываем соединение, мы получаем первые строки 1e5, запустив read.csv(con, nrow=1e5,...), затем, чтобы получить второй кусок, мы также запускаем read.csv(con, nrow=1e5,...) и т.д....

Если мы не использовали соединения, мы получим первый кусок тем же способом, read.csv("file.csv", nrow=1e5,...), однако для следующего фрагмента нам понадобится read.csv("file.csv", skip = 1e5, nrow=2e5,...). Ясно, что это неэффективно. Нам нужно снова найти строку 1e5 + 1, несмотря на то, что мы просто читаем строку 1e5.

Обратите внимание, что этот подход также неловко параллелен. Простая база данных не может работать параллельно. Конечно, Hadoop, обходит эту проблему. Независимо от того, этот подход можно сделать быстро параллельно. Просто помните, что ядра на вашем компьютере имеют одну и ту же оперативную память. Не забудьте сделать куски слишком большими!

Наконец, data.table::fread отлично. Но вы не можете передавать его. Таким образом, этот подход не работает.

Я надеюсь, что это поможет кому-то.

UPDATE

Люди продолжают поднимать этот пост, поэтому я подумал, что добавлю еще одну короткую мысль. Новый readr::read_csv, например read.csv, может быть передан соединениям. Тем не менее, он рекламируется как примерно в 10 раз быстрее.