Поэлементная агрегация множества векторов, хранящихся в списке - PullRequest
0 голосов
/ 10 сентября 2018

У меня есть список с 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, но не удалось.

Ответы [ 3 ]

0 голосов
/ 10 сентября 2018

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

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

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

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

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

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

0 голосов
/ 10 сентября 2018

Вы можете превратить свой список в вектор, затем в матрицу и рассчитать медианы строк, используя пакет 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
...