Поэлементное агрегирование множества векторов, хранящихся в списке

У меня есть список из 30 векторов длины 25:

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

Я хотел бы найти медиану первых элементов моих 30 векторов, затем медиану вторых элементов ... и так далее, до 25-го элемента.

Я хотел бы, чтобы он возвращал вектор с 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

Я пробовал с lapply, но безуспешно.

sapply(List, median) Пожалуйста, дайте минимальный воспроизводимый пример!
jogo 10.09.2018 10:13

Вот что происходит, когда вы не приводите воспроизводимый пример. У каждого есть своя интерпретация вопроса, и каждый пытается ответить на него, исходя из своего понимания.

Ronak Shah 10.09.2018 10:24

@nico dm мой ответ неправильный?

Jimmy 10.09.2018 10:51
2
3
125
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете превратить свой список в вектор, а затем в матрицу и вычислить медианы строк с помощью пакета matrixStats:

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

Результат - вектор длины 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
Ответ принят как подходящий

Другой вариант - сначала транспонировать список, а затем использовать 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

Тот же результат, что и

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

ориентир

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
apply(t(data.frame(lst)),2,median)
Onyambu 10.09.2018 10:35

@Onyambu Спасибо за ответ. Добавил тест в свой пост.

markus 10.09.2018 15:13

ПРОИЗВОДИТЕЛЬНОСТЬ: При использовании matrixStats вы можете избежать накладных расходов, связанных с созданием матрицы, вызовом matrix(), введенным путем указания размерности матрицы с помощью аргумента dim.. Использование PoGibas2 <- function(x) matrixStats::rowMedians(unlist(x), ncol = length(x), dim. = c(length(x[[1]]), length(x))) должно быть значительно быстрее.

HenrikB 15.09.2018 04:19

Если я правильно понимаю, я бы предложил транспонировать список, чтобы у вас был список для каждой позиции элемента в вашем списке.

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

После форматирования просто вызовите функцию sapply, чтобы получить вектор медиан для каждой позиции в исходном списке:

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

Надеюсь, это поможет

Другие вопросы по теме