studio - superponer graficas en r
Alternativa rĂ¡pida para dividir en R (2)
Estoy particionando un marco de datos con split()
para usar parLapply()
para llamar a una función en cada partición en paralelo. El marco de datos tiene 1.3 millones de filas y 20 cols. Estoy dividiendo / particionando por dos columnas, ambos tipos de caracteres. Parece que hay ~ 47K ID únicos y ~ 12K códigos únicos, pero no todos los emparejamientos de ID y código coinciden. El número resultante de particiones es ~ 250K. Aquí está la línea de split()
:
system.time(pop_part <- split(pop, list(pop$ID, pop$code)))
Las particiones se alimentarán a parLapply()
siguiente manera:
cl <- makeCluster(detectCores())
system.time(par_pop <- parLapply(cl, pop_part, func))
stopCluster(cl)
He dejado que el código split()
corra solo casi una hora y no se completa. Puedo dividir solo por la ID, lo que lleva ~ 10 minutos. Además, R studio y los hilos de trabajo consumen ~ 6GB de RAM.
La razón por la que conozco el número resultante de particiones es que tengo un código equivalente en Pentaho Data Integration (PDI) que se ejecuta en 30 segundos (para todo el programa, no solo para el código "split"). No espero ese tipo de rendimiento con R, pero algo que tal vez se complete en el peor caso de 10 a 15 minutos.
La pregunta principal: ¿hay una mejor alternativa para dividir? También probé ddply()
con .parallel = TRUE
, pero también funcionó durante más de una hora y nunca se completó.
Dividir (x, f) es lento si x es un factor Yf contiene muchos elementos diferentes
Entonces, este código es rápido:
system.time(split(seq_len(1300000), sample(250000, 1300000, TRUE)))
Pero, esto es muy lento:
system.time(split(factor(seq_len(1300000)), sample(250000, 1300000, TRUE)))
Y esto es rápido nuevamente porque solo hay 25 grupos
system.time(split(factor(seq_len(1300000)), sample(25, 1300000, TRUE)))
Dividir índices en pop
idx <- split(seq_len(nrow(pop)), list(pop$ID, pop$code))
Split no es lento, por ejemplo,
> system.time(split(seq_len(1300000), sample(250000, 1300000, TRUE)))
user system elapsed
1.056 0.000 1.058
entonces, si el suyo es, supongo que hay algún aspecto de sus datos que ralentiza las cosas, por ejemplo, el ID
y el code
son factores con muchos niveles, por lo que su interacción completa, en lugar de las combinaciones de niveles que aparecen en su conjunto de datos,
> length(split(1:10, list(factor(1:10), factor(10:1))))
[1] 100
> length(split(1:10, paste(letters[1:10], letters[1:10], sep="-")))
[1] 10
o quizás te estás quedando sin memoria.
Use mclapply
lugar de parLapply
si está utilizando procesos en una máquina que no es de Windows (que supongo que es el caso, ya que solicita detectCores()
).
par_pop <- mclapply(idx, function(i, pop, fun) fun(pop[i,]), pop, func)
Conceptualmente, parece que realmente se está apuntando a pvec
(distribuir un cálculo vectorizado sobre procesadores) en lugar de a mclapply
(iterar sobre filas individuales en su marco de datos).
Además, y realmente como paso inicial, considere identificar los cuellos de botella en func
; los datos son grandes pero no tan grandes, por lo que tal vez no se necesite una evaluación paralela. ¿Tal vez ha escrito el código PDI en lugar del código R? Preste atención a los tipos de datos en el marco de datos, por ejemplo, factor frente a carácter. No es inusual obtener una aceleración de 100x entre el código R mal escrito y eficiente, mientras que la evaluación paralela es, en el mejor de los casos, proporcional a la cantidad de núcleos.