【问题标题】:Elementwise aggregation of many vectors stored in a list存储在列表中的许多向量的元素聚合
【发布时间】:2018-09-10 08:08:45
【问题描述】:

我有一个包含 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) 请给minimal reproducible example
  • 如果您不提供可重现的示例,就会发生这种情况。每个人对这个问题都有自己的解释,并尝试根据自己的理解来回答。
  • @nico dm 我的回答错了吗?

标签: r list vector aggregate lapply


【解决方案1】:

另一种选择是先转置您的列表,然后使用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)

#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 感谢您的回复。为我的帖子添加了基准。
  • 性能:使用matrixStats 时,您可以避免通过参数dim. 指定矩阵维度而引入的矩阵创建、matrix() 调用的开销。使用PoGibas2 &lt;- function(x) matrixStats::rowMedians(unlist(x), ncol = length(x), dim. = c(length(x[[1]]), length(x))) 应该会明显更快。
【解决方案2】:

您可以将列表转换为向量,然后转换为矩阵并使用 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

【讨论】:

    【解决方案3】:

    如果我理解正确,我建议转置列表,这样您就可以为列表中的每个元素位置提供一个列表。

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

    格式化后,只需调用 sapply 函数即可获取原始列表中每个位置的中值向量:

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

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-18
      • 1970-01-01
      • 2017-12-05
      • 2018-06-25
      • 2015-07-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-26
      相关资源
      最近更新 更多