Reemplazar rbind en for-loop con lapply?(2º círculo del infierno)
optimization (2)
Tengo problemas para optimizar una pieza de código R. El siguiente código de ejemplo debería ilustrar mi problema de optimización:
Algunas inicializaciones y una definición de función:
a <- c(10,20,30,40,50,60,70,80)
b <- c(“a”,”b”,”c”,”d”,”z”,”g”,”h”,”r”)
c <- c(1,2,3,4,5,6,7,8)
myframe <- data.frame(a,b,c)
values <- vector(length=columns)
solution <- matrix(nrow=nrow(myframe),ncol=columns+3)
myfunction <- function(frame,columns){
athing = 0
if(columns == 5){
athing = 100
}
else{
athing = 1000
}
value[colums+1] = athing
return(value)}
El problemático for-loop se ve así:
columns = 6
for(i in 1:nrow(myframe){
values <- myfunction(as.matrix(myframe[i,]), columns)
values[columns+2] = i
values[columns+3] = myframe[i,3]
#more columns added with simple operations (i.e. sum)
solution <- rbind(solution,values)
#solution is a large matrix from outside the for-loop
}
El problema parece ser la función rbind
. Frecuentemente recibo mensajes de error sobre el tamaño de la solution
que parece ser grande después de un tiempo (más de 50 MB). Quiero reemplazar este ciclo y el rbind
con una lista y lapply
y / o foreach. Empecé con la conversión de myframe
a una lista.
myframe_list <- lapply(seq_len(nrow(myframe)), function(i) myframe[i,])
Realmente no he llegado más allá de esto, aunque traté de aplicar esta muy buena introducción al procesamiento paralelo .
¿Cómo tengo que reconstruir for-loop sin tener que cambiar myfunction
? Obviamente estoy abierto a diferentes soluciones ...
Editar: Este problema parece ser directamente desde el segundo círculo del infierno desde el Infierno R. ¿Alguna sugerencia?
La razón por la que usar rbind
en un bucle como este es una mala práctica, es que en cada iteración amplías tu marco de datos de solution
y luego lo copias a un nuevo objeto, que es un proceso muy lento y también puede provocar problemas de memoria. Una forma de evitar esto es crear una lista, cuyo i-ésimo componente almacenará el resultado de la iteración del ciclo i-ésimo. El último paso es llamar a rbind en esa lista (solo una vez al final). Esto se verá algo así como
my.list <- vector("list", nrow(myframe))
for(i in 1:nrow(myframe)){
# Call all necessary commands to create values
my.list[[i]] <- values
}
solution <- rbind(solution, do.call(rbind, my.list))
Un poco largo para comentarios, así que lo puse aquí: Si las columns
se conocen de antemano:
myfunction <- function(frame){
athing = 0
if(columns == 5){
athing = 100
}
else{
athing = 1000
}
value[colums+1] = athing
return(value)}
apply(myframe, 2, myfunction)
Si las columns
no se proporcionan a través del entorno, puede usar:
apply(myframe, 2, myfunction, columns)
con su definición original de myfunction
.