R: Как Rbind два огромных кадре, не испугая память
-
16-10-2019 - |
Вопрос
У меня есть два рамы данных df1
а также df2
Каждый из них имеет около 10 миллионов рядов и 4 столбца. Я читаю их в r, используя Rodbc/sqlquery без проблем, но когда я пытаюсь rbind
их, я получаю это самое страшное из сообщений об ошибках R: cannot allocate memory
. Анкет Должны быть более эффективные способы сделать rbind
Более эффективно - у кого -нибудь есть свои любимые уловки в этом, которым они хотят поделиться? Например, я нашел этот пример в DOC для sqldf
:
# rbind
a7r <- rbind(a5r, a6r)
a7s <- sqldf("select * from a5s union all select * from a6s")
Это лучший/рекомендуемый способ сделать это?
ОБНОВИТЬЯ получил его работать, используя решающий dbname = tempfile()
аргумент в sqldf
звоните выше, как предлагает JD Long в своем ответе этот вопрос
Решение
Вместо того, чтобы читать их в R в начале, а затем объединить их, вы могли бы прочитать их и комбинировать их, прежде чем отправить их на 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
. Анкет Здесь мы использовали значения по умолчанию, так что это было меньше.
Другие советы
Обратите внимание на data.table
R пакет для эффективных операций на объектах с более чем несколькими миллионами записей.
Версия 1.8.2 этого пакета предлагает rbindlist
функция, через которую вы можете достичь того, что вы хотите очень эффективно. Таким образом, вместо rbind(a5r, a6r)
Вы можете:
library(data.table)
rbindlist(list(a5r, a6r))
Попробуйте создать 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
Расбор объекта без предварительного выделения его размеров ... Я не уверен, что это всего лишь предположение. Сегодня вечером я расчесываю "r adferno" или "манипулирование данными с R". Может быть merge
сделает свое дело ...
РЕДАКТИРОВАТЬ
И вы должны иметь в виду, что (возможно) ваша система и/или R не могут справиться с чем -то таким большим. Попробуйте Revolution, может быть, вам удастся сэкономить время/ресурсы.
Для полноты в этой теме по теме Union: ING большие файлы, попробуйте использовать команды Shell в файлах для их объединения. В Windows есть команда «Копировать» с флагом/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-Commands при картировании потоков данных.