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

R: как объединить два огромных кадра данных без исчерпания памяти

У меня есть два кадра данных df1 и df2, каждый из которых содержит около 10 миллионов строк и 4 столбца. Я читал их в R, используя RODBC/sqlQuery, без проблем, но когда я пытаюсь rbind их, я получаю, что больше всего боюсь сообщений об ошибках R: cannot allocate memory. Там должны быть более эффективные способы сделать rbind более эффективно - у кого есть свои любимые трюки по этому поводу, которые они хотят поделиться? Например, я нашел этот пример в документе для sqldf:

# rbind
a7r <- rbind(a5r, a6r)
a7s <- sqldf("select * from a5s union all select * from a6s")

Это лучший/рекомендуемый способ сделать это?

UPDATE Я получил его для работы с использованием ключевого аргумента dbname = tempfile() в вызове sqldf выше, поскольку JD Long предлагает в своем ответе этот вопрос

4b9b3361

Ответ 1

Вместо того, чтобы читать их в R в начале, а затем объединять их, вы могли бы SQLite прочитать их и объединить их перед отправкой их в R. Таким образом, файлы никогда не будут индивидуально загружаться в R.

# create two sample files
DF1 <- data.frame(A = 1:2, B = 2:3)
write.table(DF1, "data1.dat", sep = ",", quote = FALSE)
rm(DF1)

DF2 <- data.frame(A = 10:11, B = 12:13)
write.table(DF2, "data2.dat", sep = ",", quote = FALSE)
rm(DF2)

# now we do the real work
library(sqldf)

data1 <- file("data1.dat")
data2 <- file("data2.dat")

sqldf(c("select * from data1", 
 "insert into data1 select * from data2", 
 "select * from data1"), 
 dbname = tempfile())

Это дает:

>  sqldf(c("select * from data1", "insert into data1 select * from data2", "select * from data1"), dbname = tempfile())
   A  B
1  1  2
2  2  3
3 10 12
4 11 13

Эта более короткая версия также работает, если порядок строк неважен:

sqldf("select * from data1 union select * from data2", dbname = tempfile())

Для получения дополнительной информации см. домашнюю страницу sqldf http://sqldf.googlecode.com и ?sqldf. Обратите особое внимание на аргументы формата файла, так как они близки, но не идентичны read.table. Здесь мы использовали значения по умолчанию, поэтому проблема была меньше.

Ответ 2

Обратите внимание на пакет data.table R для эффективных операций над объектами с более чем несколькими миллионами записей.

Версия 1.8.2 этого пакета предлагает функцию rbindlist, благодаря которой вы можете добиться того, что вы хотите очень эффективно. Таким образом, вместо rbind(a5r, a6r) вы можете:

library(data.table)
rbindlist(list(a5r, a6r))

Ответ 3

Попробуйте создать data.frame нужного размера, поэтому импортируйте свои данные с помощью индексов.

dtf <- as.data.frame(matrix(NA, 10, 10))
dtf1 <- as.data.frame(matrix(1:50, 5, 10, byrow=TRUE))
dtf2 <- as.data.frame(matrix(51:100, 5, 10, byrow=TRUE))
dtf[1:5, ] <- dtf1
dtf[6:10, ] <- dtf2

Я предполагаю, что rbind вырастает объект без предварительного выделения его размеров... Я не уверен, это всего лишь предположение. Сегодня вечером я расчешу "The R Inferno" или "Data Manipulation with R". Может быть, merge выполнит трюк...

ИЗМЕНИТЬ

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

Ответ 4

Для полноты этой темы на тему объединения: в больших файлах попробуйте использовать команды оболочки для файлов, чтобы их объединить. В окнах, которые являются командой "COPY" с флагом "/B". Пример:

system(command =
         paste0(
           c("cmd.exe /c COPY /Y"
             , '"file_1.csv" /B'
             , '+ "file_2.csv" /B'
             , '"resulting_file.csv" /B'
           ), collapse = " "
         )
)#system

Требуется, чтобы файлы не имели заголовка и того же разделителя и т.д. и т.д. Скорость и универсальность команд оболочки иногда являются большим преимуществом, поэтому не забывайте CLI-команды при отображении потоков данных.