2012-02-19 5 views
14

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

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

Благодаря комментаторам за указание на то, что я могу потенциально читать весь файл, используя некоторые большие трюки памяти: Quickly reading very large tables as dataframes in R

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

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

+2

Это подробно обсуждалось здесь, в частности, ответ Дж. Д. Лонга весьма полезен: http://stackoverflow.com/questions/1727772/quickly-reading-very-large-tables-as-dataframes-in-r –

+0

ff пакет делает кадры данных – mdsumner

+0

Извините, что отвечает на первый вопрос. По-видимому, мой SO search-fu нуждается в хонинговании, так как я искал, но не смог его найти. Это оставляет второй без ответа, хотя: как читать в. CSV-файле в кусках. –

ответ

8

Вы можете прочитать его в базе данных, используя 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 home page.

+0

Очень круто. Все еще кажется немного неэффективным, хотя читать весь файл и сбрасывать большую часть его. Он предполагает, что я мог бы просто подстроить его до состояния, которое я хочу в SQL, хотя, вероятно, решает мою проблему. –

+1

Если вам нужно только подмножить его до определенного набора строк, вы можете просто использовать 'read.table (..., skip = ..., nrows = ...)' –

+0

Я забыл об этом. Ничего себе, на самом деле вопрос не прошел день. Но из этого я узнал две вещи (пакет 'ff' и' sqldf' оба имеют опцию фильтра), поэтому, возможно, стоит того. –

20

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

1) Откройте подключение к файлу

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

2) Читать в куски кода с read.csv

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

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

3) Делайте то, что когда-нибудь вам нужно сделать

4) Repeat.

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.

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

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

UPDATE

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

+2

fread заплатил поддержку соединения в следующей стабильной версии, подробнее в [data.table # 561] (https://github.com/Rdatatable/data.table/issues/561) – jangorecki

+2

Обратите внимание, что 'read * 'функции пакета' iotools' могут быть связаны с соединением. – lmo

Смежные вопросы