【问题标题】:Convert list of matrices of the same order to a array将相同顺序的矩阵列表转换为数组
【发布时间】:2015-02-05 08:40:34
【问题描述】:

我有一个列表(100 个成员),每个成员都是一个 4*2 矩阵。如何将此列表转换为维度为 400*2 的数组,而无需在 R 中使用循环?

例如

A<-list()


A[[1]] 
        x         y
    85.56384 27.97745
    85.58448 28.02133
    85.60252 27.96366
    85.62318 28.00753

以此类推,最后

A[[100]]
         x         y
     85.58448 28.02133
     85.60500 28.06502
     85.62317 28.00754
     85.64372 28.05122

我想拥有 一个

      x         y
    85.56384 27.97745
    85.58448 28.02133
    85.60252 27.96366
    85.62318 28.00753
         :        :
    85.58448 28.02133
    85.60500 28.06502
    85.62317 28.00754
    85.64372 28.05122

感谢您的帮助。

【问题讨论】:

  • 添加复制示例。
  • 我建议 rbindlist 来自 data.table 包或 unnest 来自 tidyr 包。以here为例
  • @Pascal 感谢您的关注。您能否建议如何修改答案代码(在提到的链接中给出)可以用来解决我的问题?它处理的是向量列表,而不是直接扩展到任何顺序矩阵的情况。
  • @DavidArenburg:您的建议非常适合 data.frame 对象列表,但它们不适用于 matrix 对象列表。转换为 data.frame 所需的时间比 rbind 长。

标签: r list matrix


【解决方案1】:

这是对建议的不同策略的基准测试。如果您有新的想法/策略,请随时更新。

# packages
require(data.table)
require(tidyr)
require(microbenchmark)

# data
lst <- replicate(100, matrix(rnorm(16), ncol = 4), simplify = FALSE)
# benchmark test
microbenchmark(
  do.call(rbind, lst), 
  Reduce(rbind, lst), 
  apply(simplify2array(lst), 2, rbind), 
  rbindlist(lapply(lst, data.frame)), 
  unnest(lapply(lst, data.frame))
  )

结果:

Unit: microseconds
                                 expr       min         lq        mean     median        uq       max neval  
                  do.call(rbind, lst)    43.290    47.9760    55.63858    52.8845    62.703   101.307   100  
                   Reduce(rbind, lst)   542.236   570.7985   620.99652   585.3020   610.518  1871.272   100  
 apply(simplify2array(lst), 2, rbind)   311.061   345.2010   382.22978   368.6315   388.268  1563.782   100  
   rbindlist(lapply(lst, data.frame)) 11827.884 12472.3190 13092.57937 12823.0995 13595.841 15833.736   100   
      unnest(lapply(lst, data.frame)) 12371.905 12927.9765 13514.24261 13236.1360 14008.655 16121.143   100  

出于好奇,我也对data.frame 输入进行了这些基准测试,结果却大不相同:

# packages
require(data.table)
require(tidyr)
require(microbenchmark)
# data
lst <- replicate(100, as.data.frame(matrix(rnorm(16), ncol = 4)), simplify=FALSE)
# benchmark test
microbenchmark(
  do.call(rbind, lst), 
  Reduce(rbind, lst), 
  apply(simplify2array(lapply(lst, as.matrix)), 2, rbind), 
  rbindlist(lst), 
  unnest(lst)
)

结果:

Unit: microseconds
                                                    expr       min         lq       mean    median        uq        max neval 
                                     do.call(rbind, lst) 12406.716 12944.2660 13746.8552 13571.966 14564.056  16333.128   100    
                                      Reduce(rbind, lst) 36316.866 38450.7765 39894.9806 39299.610 40325.395 100949.158   100    
 apply(simplify2array(lapply(lst, as.matrix)), 2, rbind)  9577.717  9940.9930 10273.8674 10065.059 10291.996  12114.846   100    
                                          rbindlist(lst)   324.896   369.0770   397.7828   402.995   426.202    500.732   100  
                                             unnest(lst)   926.487   974.9095  1011.7322  1010.834  1033.596   1171.051   100 

【讨论】:

    【解决方案2】:

    你可以使用Reduce:

    > lst=list(matrix(1:16, ncol=4), matrix(4:23, ncol=4))
    [[1]]
         [,1] [,2] [,3] [,4]
    [1,]    1    5    9   13
    [2,]    2    6   10   14
    [3,]    3    7   11   15
    [4,]    4    8   12   16
    
    [[2]]
         [,1] [,2] [,3] [,4]
    [1,]    4    9   14   19
    [2,]    5   10   15   20
    [3,]    6   11   16   21
    [4,]    7   12   17   22
    [5,]    8   13   18   23
    
    > Reduce(rbind, lst)
          [,1] [,2] [,3] [,4]
     [1,]    1    5    9   13
     [2,]    2    6   10   14
     [3,]    3    7   11   15
     [4,]    4    8   12   16
     [5,]    4    9   14   19
     [6,]    5   10   15   20
     [7,]    6   11   16   21
     [8,]    7   12   17   22
     [9,]    8   13   18   23
    

    根据@Roland 的建议,避免使用Reduce :)

    #> lst=lapply(1:100000, function(u) m+u)
    #> system.time(do.call(rbind, lst))
    #   user  system elapsed 
    #   0.37    0.01    0.39 
    #> system.time(Reduce(rbind, lst))
    #   user  system elapsed 
    # 704.94   38.66  743.96 
    

    【讨论】:

    • do.call(rbind, lst) 应该更高效。
    • 你能解释一下为什么它比 Reduce 更有效吗? (我相信你 :) 但想知道原因)
    • Reduce 会调用rbind n-1 次,do.call 只会调用一次。我没有对它进行基准测试,但我希望后者更有效。
    • 不错,效率极低。正如@David 所说,rbindlist 确实更好!
    • 感谢您的回答。
    【解决方案3】:

    #最简单的解决方案

    lst <- replicate(100, matrix(rnorm(16), ncol=4), simplify=FALSE)
    
    mat_array <- do.call(rbind, lst) #this is the answer
    
    ra<-simplify2array(lst) #collection of matrices in an array
    
    dim(ra)
    
    #[1]   4   4 100
    

    Help function for simplify2array

    【讨论】:

    • 这将返回一个包含 400 个向量的列表,每个向量的长度为 4。这不是 OP 所要求的。
    • 实际上创建了 4 x 4 的 100 个矩阵。但上面的修改后的答案解决了这个问题。感谢您指出这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 2010-12-03
    相关资源
    最近更新 更多