2011-01-21 7 views
15

Tengo dos marcos de datos df1 y df2 que tienen aproximadamente 10 millones de filas y 4 columnas. Los leí en R usando RODBC/sqlQuery sin problemas, pero cuando trato de rbind ellos, obtengo los mensajes de error más temidos de R: cannot allocate memory. Tiene que haber formas más eficientes de hacer un rbind de manera más eficiente: ¿alguien tiene sus trucos favoritos sobre esto que quiere compartir? Por ejemplo me encontré con este ejemplo en el documento de sqldf:R: cómo enlazar dos enormes marcos de datos sin quedarse sin memoria

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

es eso de la mejor manera/recomienda para hacerlo?

ACTUALIZACIÓN que tengo que trabajar con el argumento fundamental dbname = tempfile() en la llamada sqldf anterior, como sugiere JD largo en su respuesta a this question

+0

¿Has intentado preasignar? – aL3xa

+0

Buena idea, ¿cómo hago eso? ¿Quiere decir usar algo como 'memory.limit (size = 4000)'? –

+0

No. Por cierto, eso funciona solo en Windows. Ver mi respuesta a continuación. – aL3xa

Respuesta

23

En lugar de leerlos en R al principio y luego la combinación de ellos podría tener SQLite los leyó y combinarlos antes de enviarlos a R. De esta manera los archivos nunca se cargan individualmente en 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()) 

esto da:

> 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 

esta versión más corta también funciona si orden de las filas no es importante:

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

Consulte la página de inicio sqldf http://sqldf.googlecode.com y ?sqldf para obtener más información. Preste especial atención a los argumentos de formato de archivo, ya que están cerca pero no son idénticos a read.table. Aquí hemos utilizado los valores predeterminados, por lo que fue un problema menor.

+0

Acercamiento neto ... ¡SQL es definitivamente capaz de masticar algo tan grande! – aL3xa

+0

Muy útil, gracias @Gabor ... Tengo los datos en una base de datos SQL real, y leer todo el asunto con una consulta fue regar la memoria, razón por la cual tuve que leer cada mitad en R primero usando 'RODBC/sqlQuery '(No me preguntes por qué se ahogó en todo, pero no se ahogó cuando leí cada mitad). Pero estoy de acuerdo en que si mis datos originales están en dos archivos planos, la suya es la mejor manera de leerlos, y evitar tener las dos partes en la memoria R. –

1

intenta crear una data.frame del tamaño deseado, por lo tanto, la importación tus datos usando subíndices.

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 

supongo que crece rbind objeto sin pre-asignación de sus dimensiones ... No estoy completamente seguro, esto es sólo una conjetura. Peinaré "The R Inferno" o "Data Manipulation with R" esta noche. Tal vez merge hará el truco ...

EDITAR

y usted debe desnudo en cuenta que (tal vez) el sistema y/o R no pueden hacer frente a algo tan grande. Pruebe RevolutionR, tal vez logre ahorrar tiempo/recursos.

+0

Sugerencia interesante, gracias. Lo intentaré. (No quiero ir más allá de la R gratuita, así que Revo no es una opción para mí) –

+1

sugerencia interesante, pero usa mucha más memoria que rbind. –

15

Observe el paquete data.table R para operaciones eficientes en objetos con más de varios millones de registros.

La versión 1.8.2 de ese paquete ofrece la función rbindlist a través de la cual puede lograr lo que quiere de manera muy eficiente. Así, en lugar de rbind(a5r, a6r) puede:

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

¿Se puede hacer esto sin cargar primero el conjunto de datos en la memoria? – panterasBox

1

Para completar en este hilo sobre el tema de la unión: ing archivos de gran tamaño, trate de usar los comandos de shell en los archivos de combinarlos. En Windows, el comando es "COPIA" con el indicador "/ B".Ejemplo:

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

requiere que los archivos no tienen cabecera, y el mismo delimitador, etc, etc La velocidad y la versatilidad de comandos shell veces es un gran beneficio, por lo que no se olvide de la CLI-comandos de hacer el mapa de flujos de datos a cabo.

Cuestiones relacionadas