Tengo una lista con 30 vectores de longitud 25:

lst <- replicate(30, 1:25, FALSE)

Me gustaría encontrar la mediana de los primeros elementos de mis 30 vectores, luego la mediana de los segundos elementos ... y así sucesivamente, hasta el elemento 25.

Me gustaría que devuelva un vector con los 25 valores

El resultado para el ejemplo simple de arriba leería

#[1] 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

Lo intenté con lapply pero no tuve éxito.

-2
nico dm 10 sep. 2018 a las 11:08

3 respuestas

La mejor respuesta

Otra opción es transponer su lista primero, luego usar sapply

lst <- list(a = 1:3,
            b = 1:3,
            c = 1:3,
            d = 1:3)

sapply(data.table::transpose(lst), median)
#[1] 1 2 3

Mismo resultado que

apply(do.call(rbind, lst), 2, median)

punto de referencia

set.seed(1)
n <- 1e5
lst <- replicate(n = n, expr = sample(100), simplify = FALSE)

library(microbenchmark)

markus1 <- function(x) sapply(data.table::transpose(x), median)
markus2 <- function(x) apply(do.call(rbind, x), 2, median)
Onyambu <- function(x) apply(t(data.frame(x)), 2, median)
PoGibas <- function(x) matrixStats::rowMedians(matrix(unlist(x), ncol = length(x)))
PoGibas2 <- function(x) matrixStats::rowMedians(unlist(x), ncol = length(x), dim. = c(length(x[[1]]), length(x)))
Maik <- function(x) sapply(lapply(1:length(x[[1]]), function(j) sapply(x, "[[", j)), median)

benchmark <- microbenchmark(
  markus1(lst),
  markus2(lst),
  Onyambu(lst), 
  PoGibas(lst),
  PoGibas2(lst),
  Maik(lst),
  times = 100
)

autoplot.microbenchmark(benchmark)

enter image description here

#Unit: milliseconds
#          expr        min         lq       mean     median         uq        max neval
#  markus1(lst)   218.6485   263.9614   303.5073   302.1517   329.9800   552.4448   100
#  markus2(lst)   417.4680   509.9305   552.8606   541.3165   571.3282   823.5757   100
#  Onyambu(lst) 11038.8465 11492.1539 11972.0715 11718.6827 12193.1600 15751.3892   100
#  PoGibas(lst)   257.9104   276.8268   336.9063   344.8842   379.1340   513.6330   100
# PoGibas2(lst)   238.3503   251.9929   274.8687   257.5234   276.5978   486.7224   100
#     Maik(lst)  6423.6823  6728.7237  7044.0386  6863.9510  7222.4687  9070.8505   100
2
markus 15 sep. 2018 a las 10:44

Si entiendo correctamente, sugeriría transponer la lista, para que tenga una lista para cada una de las posiciones de los elementos en su lista.

transpose = lapply(1:length(your_list[[1]]), function(j) sapply(your_list, "[[", j))

Una vez formateado, simplemente llame a una función sapply para obtener un vector de las medianas para cada posición en su lista original:

result = sapply(transpose, function(x) median(x))

Espero que ayude

1
Maik 10 sep. 2018 a las 08:22

Puede convertir su lista en un vector para luego matricular y calcular medianas de fila usando el paquete matrixStats:

foo <- list(1:25, 1:25, 1:25)
matrixStats::rowMedians(matrix(unlist(foo), ncol = length(foo)))

El resultado es un vector de longitud 25:

[1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
1
PoGibas 10 sep. 2018 a las 08:15