2011-01-21 3 views
15

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

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

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

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

+0

Вы пытались предварительно выделить? – aL3xa

+0

Хорошая идея - как мне это сделать - вы имеете в виду использование чего-то типа 'memory.limit (size = 4000)'? –

+0

№ BTW, который работает только в Windows. См. Мой ответ ниже. – aL3xa

ответ

23

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

+0

Уютный подход ... SQL определенно способен пережевывать что-то такое большое! – aL3xa

+0

Очень полезно, спасибо @Gabor ... У меня есть данные в реальной базе данных SQL, и чтение всего этого с помощью одного запроса шло по моей памяти, поэтому мне пришлось читать каждую половину в R сначала с помощью 'RODBC/sqlQuery '(не спрашивайте меня, почему это задушило все это, но не задушило, когда я читал каждую половину). Но я согласен с тем, что мои исходные данные находятся в двух плоских файлах, ваш лучший способ их считывания и избегать использования двух частей в памяти R. –

1

Try создать 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 будет делать трюк ...

EDIT

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

+0

Интересное предложение, спасибо. Я это попробую. (Я не хочу идти за рамки бесплатного R, хотя, поэтому Revo для меня не вариант) –

+1

интересное предложение, но оно использует гораздо больше памяти, чем rbind. –

15

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

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

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

Можете ли вы сделать это, не загружая сначала набор данных в память? – panterasBox

1

Для полноты в этой теме по теме объединения: ИНГ больших файлов, попробуйте использовать команды оболочки на файлы, чтобы объединить их. В окнах, которые являются командой «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-команду при намечая потоки данных.

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