secuencia - paralelizador de jelenko
¿Puede rbind ser paralelizado en R? (5)
Aquí hay una solución que, naturalmente, se extiende a rbind.fill, fusionar y otras funciones de la lista de marcos de datos:
Pero al igual que con todas mis respuestas / preguntas verifico :)
require(snowfall)
require(rbenchmark)
rbinder <- function(..., cores=NULL){
if(is.null(cores)){
do.call("rbind", ...)
}else{
sequ <- as.integer(seq(1, length(...), length.out=cores+1))
listOLists <- paste(paste("list", seq(cores), sep=""), " = ...[", c(1, sequ[2:cores]+1), ":", sequ[2:(cores+1)], "]", sep="", collapse=", ")
dfs <- eval(parse(text=paste("list(", listOLists, ")")))
suppressMessages(sfInit(parallel=TRUE, cores))
dfs <- sfLapply(dfs, function(x) do.call("rbind", x))
suppressMessages(sfStop())
do.call("rbind", dfs)
}
}
pieces <- lapply(seq(1000), function(.) data.frame(matrix(runif(1000), ncol=1000)))
benchmark(do.call("rbind", pieces), rbinder(pieces), rbinder(pieces, cores=4), replications = 10)
#test replications elapsed relative user.self sys.self user.child sys.child
#With intel i5 3570k
#1 do.call("rbind", pieces) 10 116.70 6.505 115.79 0.10 NA NA
#3 rbinder(pieces, cores = 4) 10 17.94 1.000 1.67 2.12 NA NA
#2 rbinder(pieces) 10 116.03 6.468 115.50 0.05 NA NA
Mientras estoy sentado aquí esperando que se ejecuten algunos scripts de R ... Me preguntaba ... ¿hay alguna forma de paralelizar rbind en R?
Estoy sentado esperando a que esta llamada se complete con frecuencia mientras trato con grandes cantidades de datos.
do.call("rbind", LIST)
Como dijo que desea data.frame
objetos data.frame
, debe usar el paquete data.table
. Tiene una función llamada rbindlist
que mejora drásticamente el rbind
. No estoy 100% seguro, pero apostaría a que cualquier uso de rbind
una copia cuando rbindlist
no lo hace. De todos modos, un data.table
es un data.frame
para que no pierdas nada para probar.
EDITAR:
library(data.table)
system.time(dt <- rbindlist(pieces))
utilisateur système écoulé
0.12 0.00 0.13
tables()
NAME NROW MB COLS KEY
[1,] dt 1,000 8 X1,X2,X3,X4,X5,X6,X7,X8,...
Total: 8MB
Velocidad del rayo...
Dudo que puedas hacer que esto funcione más rápido al paralelizarlo: aparte del hecho de que probablemente tendrías que escribirlo tú mismo (enhebre uno de los primeros elementos 1 y 2 de rbinds, mientras que otros elementos 3 y 4 de rbinds, y cuándo) están listos, los resultados son ''rebote'', algo así - no veo una forma no-C de mejorar esto), va a implicar copiar grandes cantidades de datos entre tus hilos, que suele ser la cosa Eso va lento en primer lugar.
En C, puede compartir objetos entre subprocesos, por lo que puede hacer que todos sus subprocesos escriban en la misma memoria. Te deseo la mejor de las suertes con eso :-)
Por último, a un lado: rbinding data.frames es simplemente lento. Si sabe por adelantado que la estructura de todos sus datos. Los cuadros son exactamente iguales y no contiene columnas de caracteres puros, probablemente pueda usar el truco de esta respuesta para una de mis preguntas . Si su data.frame contiene columnas de caracteres, sospecho que es mejor tratarlas por separado ( do.call(c, lapply(LIST, "[[", "myCharColName"))
) y luego realizar el truco con el resto, después de Que se les puede reunir.
Esto se está expandiendo en la respuesta de @Dominik.
Podemos usar el paquete mclapply del paquete paralelo para aumentar aún más la velocidad. También rbind.fill hace un mejor trabajo que rbind, así que aquí está el código mejorado. NOTA: esto solo funcionará en mac / linux. mclapply no es compatible con Windows. EDITAR: si desea ver el progreso, elimine el comentario de la línea de impresión (i) y asegúrese de ejecutar desde un terminal, no desde RStudio. Imprimiendo a RStudio desde un proceso paralelo, tipo de desorden RStudio up.
library(parallel)
rbind.fill.parallel <- function(list){
while(length(list) > 1) {
idxlst <- seq(from=1, to=length(list), by=2)
list <- mclapply(idxlst, function(i) {
#print(i) #uncomment this if you want to see progress
if(i==length(list)) { return(list[[i]]) }
return(rbind.fill(list[[i]], list[[i+1]]))
})
}
}
No he encontrado una manera de hacer esto en paralelo hasta ahora. Sin embargo, para mi conjunto de datos (esta es una lista de aproximadamente 1500 marcos de datos con un total de 4.5 millones de filas) el siguiente fragmento de código pareció ayudar:
while(length(lst) > 1) {
idxlst <- seq(from=1, to=length(lst), by=2)
lst <- lapply(idxlst, function(i) {
if(i==length(lst)) { return(lst[[i]]) }
return(rbind(lst[[i]], lst[[i+1]]))
})
}
donde lst es la lista Parecía ser 4 veces más rápido que usar do.call(rbind, lst)
o incluso do.call(rbind.fill, lst)
(con rbind.fill del paquete plyr). En cada iteración, este código está reduciendo a la mitad la cantidad de marcos de datos.