Обрезка огромного (3,5 ГБ) файла csv для чтения в R

Итак, у меня есть файл данных (разделенный точкой с запятой), в котором много деталей и неполных строк (ведущий Access и SQL для подавления). Этот набор данных уровня графства разбит на сегменты, подсегменты и подсегменты (всего на 200 факторов) в течение 40 лет. Короче говоря, он огромный, и он не собирается вписываться в память, если я попытаюсь просто прочитать его.

Итак, мой вопрос заключается в том, что я хочу, чтобы все графства, но всего один год (и только самый высокий уровень сегмента..., что привело к примерно 100 000 строк в конце), что было бы лучшим способом переходите к тому, чтобы этот сверток в R?

В настоящее время я пытаюсь вырезать нерелевантные годы с Python, обойдя ограничение размера файлов, читая и работая по одной строке за раз, но я бы предпочел решение R-only (пакеты CRAN в порядке). Есть ли аналогичный способ чтения в файлах фрагмента за раз в R?

Будем очень благодарны за любые идеи.

Update:

  • Ограничения
    • Нужно использовать мою машину, поэтому никаких экземпляров EC2
    • Как только R-только возможно. Скорость и ресурсы в этом случае не являются проблемой... если моя машина не взрывается...
    • Как вы можете видеть ниже, данные содержат смешанные типы, которые мне нужно использовать позже
  • Данные
    • Данные 3,5 ГБ, около 8,5 миллионов строк и 17 столбцов.
    • Несколько тысяч строк (~ 2k) искажены, причем только один столбец вместо 17
      • Это совершенно неважно и их можно отбросить
    • Мне нужно только ~ 100 000 строк из этого файла (см. ниже)

Пример данных:

County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP; ...
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1; ...
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5; ...
NC  [Malformed row]
[8.5 Mill rows]

Я хочу вырезать несколько столбцов и выбрать два из 40 доступных лет (2009-2010 с 1980 по 2020 год), чтобы данные могли вписаться в R:

County; State; Year; Quarter; Segment; GDP; ...
Ada County;NC;2009;4;FIRE;80.1; ...
Ada County;NC;2010;1;FIRE;82.5; ...
[~200,000 rows]

Результаты:

После того, как все предложения были внесены, я решил, что readLines, предложенный JD и Marek, будет работать лучше всего. Я дал Мареку чек, потому что он дал примерную реализацию.

Я воспроизвел слегка адаптированную версию реализации Marek для моего окончательного ответа здесь, используя strsplit и cat, чтобы сохранить только столбцы, которые я хочу.

Также следует отметить, что это намного эффективнее, чем Python... как в Python chomps через файл 3,5 ГБ за 5 минут, в то время как R занимает около 60... но если все, что у вас есть, это R, то это билет.

## Open a connection separately to hold the cursor position
file.in <- file('bad_data.txt', 'rt')
file.out <- file('chopped_data.txt', 'wt')
line <- readLines(file.in, n=1)
line.split <- strsplit(line, ';')
# Stitching together only the columns we want
cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
## Use a loop to read in the rest of the lines
line <- readLines(file.in, n=1)
while (length(line)) {
  line.split <- strsplit(line, ';')
  if (length(line.split[[1]]) > 1) {
    if (line.split[[1]][3] == '2009') {
        cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
    }
  }
  line<- readLines(file.in, n=1)
}
close(file.in)
close(file.out)

Отказы по подходу:

  • sqldf
    • Это определенно то, что я буду использовать для этого типа проблемы в будущем, если данные будут хорошо сформированы. Однако, если это не так, то SQLite дросселирует.
  • MapReduce
    • Честно говоря, docs запугали меня в этом немного, поэтому я не стал его пытаться. Похоже, что объект также должен был быть в памяти, что бы победить точку, если бы это было так.
  • bigmemory
    • Этот подход полностью связан с данными, но он может обрабатывать только один тип за раз. В результате все мои векторы персонажей упали, когда помещены в большую таблицу. Если мне нужно создавать большие наборы данных для будущего, я бы рассмотрел только использование чисел, чтобы сохранить этот вариант в живых.
  • сканирования
    • У сканирования, похоже, были проблемы с подобным типом, такие как большая память, но со всеми механиками readLines. Короче говоря, это просто не соответствовало законопроекту на этот раз.

Ответ 1

Моя попытка с readLines. Этот фрагмент кода создает csv с выбранными годами.

file_in <- file("in.csv","r")
file_out <- file("out.csv","a")
x <- readLines(file_in, n=1)
writeLines(x, file_out) # copy headers

B <- 300000 # depends how large is one pack
while(length(x)) {
    ind <- grep("^[^;]*;[^;]*; 20(09|10)", x)
    if (length(ind)) writeLines(x[ind], file_out)
    x <- readLines(file_in, n=B)
}
close(file_in)
close(file_out)

Ответ 2

Есть ли аналогичный способ чтения в файлах фрагмента за раз в R?

Да. Функция readChar() будет считываться в блоке символов, не предполагая, что они завершены нулем. Если вы хотите читать данные в строке за раз, вы можете использовать readLines(). Если вы читаете блок или строку, выполните операцию, а затем напишите данные, вы можете избежать проблемы с памятью. Хотя, если вам нравится запускать большой экземпляр памяти на Amazon EC2, вы можете получить до 64 ГБ оперативной памяти. Это должно содержать ваш файл плюс много места для манипулирования данными.

Если вам нужна более высокая скорость, то рекомендация Шейна по использованию Map Reduce - очень хорошая. Однако, если вы идете по пути использования большого экземпляра памяти в EC2, вы должны посмотреть на многоядерный пакет для использования всех ядер на машине.

Если вы хотите прочитать много концертов с разделительными данными в R, вы должны хотя бы исследовать пакет sqldf, который позволяет импортировать непосредственно в sqldf из R, а затем работать с данными из R. Я нашел sqldf быть одним из самых быстрых способов импорта концертов данных в R, как упоминалось в этом предыдущем вопросе.

Ответ 3

Я не эксперт в этом, но вы можете подумать о том, чтобы попробовать MapReduce, что в основном означало бы "разделить и победить" " подход. R имеет несколько вариантов для этого, включая:

В качестве альтернативы R предоставляет несколько пакетов для обработки больших данных, которые выходят за пределы памяти (на диск). Вероятно, вы могли бы загрузить весь набор данных в объект bigmemory и полностью выполнить сокращение внутри R. См. http://www.bigmemory.org/ для набора инструментов для обрабатывайте это.

Ответ 4

Пакет ff - это прозрачный способ работы с огромными файлами.

Вы можете увидеть пакет сайт и/или об этом.

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

Ответ 6

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

http://colbycol.r-forge.r-project.org/

Он передает любые аргументы в read.table, поэтому комбинация должна позволять вам подмножество довольно плотно.

Ответ 8

Как насчет использования readr и read_*_chunked семейства?

Итак, в вашем случае:

TestFile.CSV

County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5
lol
Ada County;NC;2013;1;FIRE;Financial;Banks;82.5

Фактический код

require(readr)
f <- function(x, pos) subset(x, Year %in% c(2009, 2010))
read_csv2_chunked("testfile.csv", DataFrameCallback$new(f), chunk_size = 1)

Это относится к каждому фрагменту f, запоминая имена col и комбинируя отфильтрованные результаты в конце. См. ?callback, который является источником этого примера.

Это приводит к:

# A tibble: 2 × 8
      County State  Year Quarter Segment `Sub-Segment` `Sub-Sub-Segment`   GDP
*      <chr> <chr> <int>   <int>   <chr>         <chr>             <chr> <dbl>
1 Ada County    NC  2009       4    FIRE     Financial             Banks   801
2 Ada County    NC  2010       1    FIRE     Financial             Banks   825

Вы даже можете увеличить chunk_size, но в этом примере есть только 4 строки.

Ответ 9

Возможно, вы можете перейти на MySQL или PostgreSQL, чтобы не допустить вас от ограничений MS Access.

Довольно легко подключить R к этим системам с помощью DBI (доступного на CRAN) основе соединителя базы данных.

Ответ 10

scan() имеет как аргумент nlines, так и аргумент пропуска. Есть ли какая-то причина, по которой вы можете просто использовать это для чтения в куске строк, проверяя дату, чтобы узнать, подходит ли она? Если входной файл упорядочен по дате, вы можете сохранить индекс, который сообщает вам, какими должны быть ваши пропуски и nlines, которые ускорят процесс в будущем.

Ответ 11

В эти дни 3,5 ГБ просто не так уж и велики, я могу получить доступ к машине с 244 ГБ оперативной памяти (r3.8xlarge) в облаке Amazon за 2,80 долл./час. Сколько часов вам понадобится, чтобы выяснить, как решить проблему с помощью решений типа больших данных? Сколько стоит ваше время? Да, вам понадобится час или два, чтобы понять, как использовать AWS, но вы можете изучить основы на свободном уровне, загрузить данные и прочитать первые 10k строк в R, чтобы проверить, работает ли это, а затем вы можете запустить большой экземпляр памяти, такой как r3.8xlarge и прочитал все это! Просто мой 2c.

Ответ 12

Теперь, 2017, я бы предложил пойти на искру и искра.

  • синтаксис может быть написан простым способом dplyr-подобным образом

  • он достаточно хорошо подходит для небольшой памяти (небольшой по смыслу 2017 года)

Однако, это может быть запугивающим опытом, чтобы начать...

Ответ 13

Я бы пошел на БД, а затем сделал несколько запросов, чтобы извлечь образцы, которые вам нужны через DBI

Пожалуйста, избегайте импортировать CSV файл 3,5 ГБ в SQLite. Или, по крайней мере, дважды проверьте, что ваш HUGE db вписывается в пределы SQLite, http://www.sqlite.org/limits.html

Это чертовски большая БД у вас. Я бы пошел на MySQL, если вам нужна скорость. Но будьте готовы ждать много часов, чтобы импорт был закончен. Если у вас нет нетрадиционного оборудования или вы пишете из будущего...

Amazon EC2 может быть хорошим решением для создания экземпляра сервера с R и MySQL.

мои две скромные достоинства.