2011-01-21 9 views
15

Ho due frame di dati df1 e df2 che ognuno ha circa 10 milioni di righe e 4 colonne. Li ho letti in R usando RODBC/sqlQuery senza problemi, ma quando provo a rbind, ottengo il più temuto dei messaggi di errore R: cannot allocate memory. Ci sono modi più efficienti per fare un rbind in modo più efficiente - qualcuno ha i suoi trucchi preferiti su questo che vuole condividere? Per esempio ho trovato questo esempio nel documento per sqldf:R: come rbindare due enormi frame di dati senza esaurire la memoria

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

è che il modo migliore/consigliato di farlo?

UPDATE ho preso a lavorare utilizzando il dbname = tempfile() argomento cruciale nella chiamata sqldf sopra, come suggerisce JD a lungo nella sua risposta a this question

+0

Hai provato a pre-allocare? – aL3xa

+0

Buona idea: come si fa? Significa usare qualcosa come "memory.limit (size = 4000)'? –

+0

No. BTW, funziona solo su Windows. Vedi la mia risposta qui sotto. – aL3xa

risposta

23

Piuttosto che leggere nella R all'inizio e poi combinandoli si potrebbe avere SQLite leggerli e combinarle prima di inviarli al R. In questo modo i file non vengono mai caricati singolarmente in 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()) 

Questo dà:

> 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 

questa versione più corta funziona anche se l'ordine di fila non è importante:

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

Vedere la home page sqldf http://sqldf.googlecode.com e ?sqldf per ulteriori informazioni. Presta particolare attenzione agli argomenti del formato file poiché sono vicini ma non identici a read.table. Qui abbiamo usato le impostazioni predefinite quindi era meno di un problema.

+0

Approccio pulito ... SQL è sicuramente in grado di masticare qualcosa di così grande! – aL3xa

+0

Molto utile, grazie a @Gabor ... Ho i dati in un vero database SQL, e la lettura dell'intera cosa con una query mi ha bloccato la memoria, motivo per cui ho dovuto leggere ogni metà in R prima usando 'RODBC/sqlQuery '(non chiedermi perché è soffocato da tutto, ma non ho soffocato quando ho letto ogni metà). Ma sono d'accordo se i miei dati originali sono in due file flat, il tuo è il modo migliore per leggerli ed evitare di avere le due parti nella memoria R. –

1

cercare di creare un data.frame di dimensione desiderata, e quindi l'importazione i tuoi dati usando gli indici.

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 

Immagino che rbind cresce oggetto senza pre-allocare le sue dimensioni ... Non sono sicuro che positivamente, questa è solo una supposizione. Riporterò "The R Inferno" o "Data Manipulation with R" stasera. Forse merge farà il trucco ...

EDIT

e si dovrebbe nudo in mente che (forse) il sistema e/o R non possono far fronte con qualcosa di così grande. Prova RevolutionR, forse riuscirai a risparmiare tempo e risorse.

+0

Suggerimento interessante, grazie. Lo proverò. (Non voglio andare oltre la R libera però, quindi Revo non è un'opzione per me) –

+1

suggerimento interessante, ma usa molta più memoria di rbind. –

15

Notare il pacchetto data.table R per operazioni efficienti su oggetti con più milioni di record.

La versione 1.8.2 di quel pacchetto offre la funzione rbindlist attraverso la quale è possibile ottenere ciò che si desidera in modo molto efficiente. Così, invece di rbind(a5r, a6r) è possibile:

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

Puoi farlo senza prima caricare il set di dati in memoria? – panterasBox

1

Per completezza in questa discussione sul tema dell'unione: ing file di grandi dimensioni, provare a utilizzare i comandi della shell sui file di combinarli. In Windows che è il comando "COPY" con il flag "/ B".Esempio:

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

richiede che i file non hanno intestazione, e lo stesso delimitatore ecc ecc La velocità e la versatilità dei comandi di shell a volte è un grande vantaggio, in modo da non dimenticate CLI-comandi quando mappatura flussi di dati.

Problemi correlati