R: Come rbind due enormi data-frame, senza esaurire la memoria
-
16-10-2019 - |
Domanda
Ho due dati fotogrammi df1
e df2
che ogni hanno circa 10 milioni di righe e 4 colonne. Li ho letti in R utilizzando RODBC / sqlquery senza problemi, ma quando provo a rbind
loro, ottengo che più temuto dei messaggi di errore R: cannot allocate memory
. Ci hanno avuto modo di essere modi più efficienti per fare un rbind
in modo più efficiente - chiunque hanno i loro trucchi preferiti su questo vogliono condividere? Per esempio ho trovato questo esempio nel documento per sqldf
:
# rbind
a7r <- rbind(a5r, a6r)
a7s <- sqldf("select * from a5s union all select * from a6s")
E 'questo il modo migliore / consigliato di farlo?
UPDATE
Ho preso al lavoro utilizzando l'argomento cruciale dbname = tempfile()
nella chiamata sqldf
sopra, come suggerisce JD lungo nella sua risposta al questa domanda
Soluzione
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())
In questo modo:
> 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())
Visualizza la pagina iniziale sqldf http://sqldf.googlecode.com e ?sqldf
per maggiori informazioni. Prestare particolare attenzione agli argomenti di formato di file in quanto sono vicini ma non identico a read.table
. Qui abbiamo utilizzato i valori di default così è stato meno di un problema.
Altri suggerimenti
Avviso il pacchetto data.table
R per operazioni efficienti su oggetti con oltre parecchi milioni di dischi.
La versione 1.8.2 di ciò che offre la funzione di pacchetti rbindlist
attraverso il quale è possibile ottenere quello che vuoi in modo molto efficiente. Così, invece di rbind(a5r, a6r)
è possibile:
library(data.table)
rbindlist(list(a5r, a6r))
Cerca di creare una data.frame
di dimensione desiderata, quindi importare i dati utilizzando 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
credo che rbind
cresce oggetto senza pre-allocare le sue dimensioni ... Non sono sicuro che positivamente, questa è solo una supposizione. Mi pettino down "L'Inferno R" o "manipolazione dei dati con R" stasera. Forse merge
farà il trucco ...
Modifica
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 riuscirete a risparmiare qualche tempo / risorse.
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 viene comando "Copia" con la bandiera "/ 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 etc etc. 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.