studio matrices filtrar filas español eliminar ejemplos datos data crear r performance list merge dataframe

matrices - Fusión vectorizada rápida de la lista de data.frames por fila



filtrar datos en r (3)

La mayoría de las preguntas sobre la fusión de data.frame en listas en SO no se relacionan exactamente con lo que intento transmitir aquí, pero pueden probar que estoy equivocado.

Tengo una lista de data.frames. Me gustaría "juntar" filas en otro data.frame por fila. En esencia, todas las primeras filas forman un data.frame, second rows second data.frame y así sucesivamente. El resultado sería una lista de la misma longitud que el número de filas en mi data.frame (s) original. Hasta ahora, los data.frames son idénticos en dimensiones.

Aquí hay algunos datos para jugar.

sample.list <- list(data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)), data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)), data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)), data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)), data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)), data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)), data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)))

Esto es lo que se me ocurrió con el buen ol ''for loop.

#solution 1 my.list <- vector("list", nrow(sample.list[[1]])) for (i in 1:nrow(sample.list[[1]])) { for (j in 1:length(sample.list)) { my.list[[i]] <- rbind(my.list[[i]], sample.list[[j]][i, ]) } } #solution 2 (so far my favorite) sample.list2 <- do.call("rbind", sample.list) my.list2 <- vector("list", nrow(sample.list[[1]])) for (i in 1:nrow(sample.list[[1]])) { my.list2[[i]] <- sample.list2[seq(from = i, to = nrow(sample.list2), by = nrow(sample.list[[1]])), ] }

¿Se puede mejorar esto utilizando la vectorización sin mucho daño cerebral? La respuesta correcta contendrá un fragmento de código, por supuesto. "Sí" como una respuesta no cuenta.

EDITAR

#solution 3 (a variant of solution 2 above) ind <- rep(1:nrow(sample.list[[1]]), times = length(sample.list)) my.list3 <- split(x = sample.list2, f = ind)

BENCHMARKING

He hecho mi lista más grande con más filas por data.frame. He comparado los resultados que son los siguientes:

#solution 1 system.time(for (i in 1:nrow(sample.list[[1]])) { for (j in 1:length(sample.list)) { my.list[[i]] <- rbind(my.list[[i]], sample.list[[j]][i, ]) } }) user system elapsed 80.989 0.004 81.210 # solution 2 system.time(for (i in 1:nrow(sample.list[[1]])) { my.list2[[i]] <- sample.list2[seq(from = i, to = nrow(sample.list2), by = nrow(sample.list[[1]])), ] }) user system elapsed 0.957 0.160 1.126 # solution 3 system.time(split(x = sample.list2, f = ind)) user system elapsed 1.104 0.204 1.332 # solution Gabor system.time(lapply(1:nr, bind.ith.rows)) user system elapsed 0.484 0.000 0.485 # solution ncray system.time(alply(do.call("cbind",sample.list), 1, .fun=matrix, ncol=ncol(sample.list[[1]]), byrow=TRUE, dimnames=list(1:length(sample.list),names(sample.list[[1]])))) user system elapsed 11.296 0.016 11.365


Aquí está mi intento con plyr, pero me gusta el enfoque de G. Grothendieck:

library(plyr) alply(do.call("cbind",sample.list), 1, .fun=matrix, ncol=ncol(sample.list[[1]]), byrow=TRUE, dimnames=list(1:length(sample.list), names(sample.list[[1]]) ))


Prueba esto:

bind.ith.rows <- function(i) do.call(rbind, lapply(sample.list, "[", i, TRUE)) nr <- nrow(sample.list[[1]]) lapply(1:nr, bind.ith.rows)


Un par de soluciones que lo harán más rápido usando data.table

EDITAR - con un conjunto de datos más grande que muestra la data.table datos. data.table más.

# here are some sample data sample.list <- replicate(10000, data.frame(x = sample(1:100, 10), y = sample(1:100, 10), capt = sample(0:1, 10, replace = TRUE)), simplify = F)

La solución rápida de Gabor:

# Solution Gabor bind.ith.rows <- function(i) do.call(rbind, lapply(sample.list, "[", i, TRUE)) nr <- nrow(sample.list[[1]]) system.time(rowbound <- lapply(1:nr, bind.ith.rows)) ## user system elapsed ## 25.87 0.01 25.92

La función rbindlist lo hará aún más rápido incluso cuando se trabaja con data.frames)

library(data.table) fastbind.ith.rows <- function(i) rbindlist(lapply(sample.list, "[", i, TRUE)) system.time(fastbound <- lapply(1:nr, fastbind.ith.rows)) ## user system elapsed ## 13.89 0.00 13.89

Una solución data.table

Aquí hay una solución que usa data.tables: es una solución split en esteroides.

# data.table solution system.time({ # change each element of sample.list to a data.table (and data.frame) this # is done instaneously by reference invisible(lapply(sample.list, setattr, name = "class", value = c("data.table", "data.frame"))) # combine into a big data set bigdata <- rbindlist(sample.list) # add a row index column (by refere3nce) index <- as.character(seq_len(nr)) bigdata[, `:=`(rowid, index)] # set the key for binary searches setkey(bigdata, rowid) # split on this - dt_list <- lapply(index, function(i, j, x) x[i = J(i)], x = bigdata) # if you want to drop the `row id` column invisible(lapply(dt_list, function(x) set(x, j = "rowid", value = NULL))) # if you really don''t want them to be data.tables run this line # invisible(lapply(dt_list, setattr,name = ''class'', value = # c(''data.frame''))) }) ################################ ## user system elapsed ## ## 0.08 0.00 0.08 ## ################################

¡Qué impresionante es data.table !

Usuario de rbindlist con rbindlist

rbindlist es rápido porque no realiza la comprobación de que do.call(rbind,....) hará. Por ejemplo, asume que las columnas de factores tienen los mismos niveles que en el primer elemento de la lista.