【问题标题】:compute sum of columns in a nested list in R计算R中嵌套列表中的列总和
【发布时间】:2017-03-30 21:20:06
【问题描述】:

我们如何对嵌套列表的元素进行列求和。我有一个 10 的嵌套列表,每个包含 50 个元素的子列表,这些元素是具有 4 列不同行数的矩阵。这是一个更简单的例子。我需要在列表中添加列。我需要一个 colsums.ll

    l1<-matrix(c(1:8),nrow=2)
    l2<-matrix(c(1:16),nrow=4)
    l<-list(l1,l2)
    ll<-list(l,l)
     ll
    [[1]]
   [[1]][[1]]
        [,1] [,2] [,3] [,4]
  [1,]    1    3    5    7
  [2,]    2    4    6    8

   [[1]][[2]]
         [,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]]
    [[2]][[1]]
         [,1] [,2] [,3] [,4]
    [1,]    1    3    5    7
    [2,]    2    4    6    8

    [[2]][[2]]
        [,1] [,2] [,3] [,4]
    [1,]    1    5    9   13
    [2,]    2    6   10   14
    [3,]    3    7   11   15
    [4,]    4    8   12   16

【问题讨论】:

  • lapply(unlist(ll, recursive = FALSE), colSums)lapply(lapply(rapply(ll, enquote, how="unlist"), eval), colSums)
  • 谢谢。但这只是对每个子矩阵的第一列求和。我需要列表中所有元素的第一列的总和。在上述情况下,答案应该是 c(26, 66, 106, 146)。

标签: r


【解决方案1】:

这里有一些方法:

1)将ll的第一级展平,取列和再取结果的行和:

rowSums(sapply(do.call(c, ll), colSums))
## [1]  26  66 106 146

2) 另一种方法是在展平之后将rbind 所有矩阵放在一起,然后取其中的colSums。请注意,与(1)相比,这个没有sapplylapply

colSums(do.call(rbind, do.call(c, ll)))
## [1]  26  66 106 146

3) 上面没有使用任何包,但可以翻译成这样使用 magrittr,其中第一个管道对应于 (1),第二个管道对应于 (2)

library(magrittr)

ll %>% do.call(what = c) %>% sapply(colSums) %>% rowSums
## [1]  26  66 106 146

ll %>% do.call(what = c) %>% do.call(what = rbind) %>% colSums
## [1]  26  66 106 146

【讨论】:

    【解决方案2】:
    colSums(do.call(rbind, lapply(lapply(rapply(ll, enquote, how="unlist"), eval), colSums)))
    [1]  26  66 106 146
    

    【讨论】:

      【解决方案3】:

      这是一个 purrr 选项:

      library(purrr)
      
      ll %>% flatten() %>%    # reduce depth to one level
          map(colSums) %>%    # get column sums of each element
          reduce(`+`)         # add respective colSums
      #> [1]  26  66 106 146
      

      或先将其简化为单个矩阵:

      ll %>% flatten() %>% reduce(rbind) %>% colSums()    
      

      或使用invoke 代替reduce,这样可以节省调用次数,但代价是语法稍差:

      ll %>% flatten() %>% invoke(rbind, .) %>% colSums()
      

      所有返回相同的东西。

      【讨论】:

        【解决方案4】:

        我喜欢基础 R 中的 Reduce,所以你可以这样做:

        Reduce("+", lapply(Reduce(c, ll), colSums))
        # [1]  26  66 106 146
        

        基准测试

        set.seed(100)
        l1 <- matrix(sample(100, 100000, replace = TRUE),ncol=1000)
        l2 <- matrix(sample(100, 1000000, replace = TRUE),ncol=1000)
        l <- list(l1,l2)
        ll <- rep(list(l), 100)
        str(ll)
        # List of 100
         # $ :List of 2
          # ..$ : int [1:100, 1:1000] 31 26 56 6 47 49 82 38 55 18 ...
          # ..$ : int [1:1000, 1:1000] 45 22 77 7 85 32 80 71 52 38 ...
         # $ :List of 2
          # ..$ : int [1:100, 1:1000] 31 26 56 6 47 49 82 38 55 18 ...
          # ..$ : int [1:1000, 1:1000] 45 22 77 7 85 32 80 71 52 38 ...
         # $ :List of 2
          # ..$ : int [1:100, 1:1000] 31 26 56 6 47 49 82 38 55 18 ...
          # ..$ : int [1:1000, 1:1000] 45 22 77 7 85 32 80 71 52 38 ...
         # $ :List of 2
          # ..$ : int [1:100, 1:1000] 31 26 56 6 47 49 82 38 55 18 ...
          # ..$ : int [1:1000, 1:1000] 45 22 77 7 85 32 80 71 52 38 ...
        

        library(purrr)
        library(microbenchmark)
        library(magrittr)
        
        f_G.Grothendieck1 <- function(ll) rowSums(sapply(do.call(c, ll), colSums)) 
        f_G.Grothendieck2 <- function(ll) colSums(do.call(rbind, do.call(c, ll)))
        f_G.Grothendieck3 <- function(ll) 
            ll %>% do.call(what = c) %>% sapply(colSums) %>% rowSums
        f_G.Grothendieck4 <- function(ll) 
            ll %>% do.call(what = c) %>% do.call(what = rbind) %>% colSums
        f_d.b <- function(ll) 
          colSums(do.call(rbind, lapply(lapply(rapply(ll, enquote, how="unlist"), eval), colSums)))
        f_alistaire1 <- function(ll) ll %>% flatten() %>%  map(colSums) %>%  reduce(`+`)
        f_alistaire2 <- function(ll) ll %>% flatten() %>% invoke(rbind, .) %>% colSums()
        f_989 <- function(ll) Reduce("+", lapply(Reduce(c, ll), colSums))
        
        r <- f_G.Grothendieck1(ll)
        # [1] TRUE
        all(r == f_G.Grothendieck2(ll))
        # [1] TRUE
        all(r == f_G.Grothendieck3(ll))
        # [1] TRUE
        all(r == f_G.Grothendieck4(ll))
        # [1] TRUE
        all(r == f_d.b(ll))
        # [1] TRUE
        all(r == f_alistaire1(ll))
        # [1] TRUE
        all(r == f_alistaire2(ll))
        # [1] TRUE
        all(r == f_989(ll))
        # [1] TRUE
        res <- microbenchmark(
        f_G.Grothendieck1(ll), f_G.Grothendieck2(ll), f_G.Grothendieck3(ll), 
        f_G.Grothendieck4(ll), f_d.b(ll), f_alistaire1(ll), f_alistaire2(ll), f_989(ll))
        

        print(res, order="mean")
            # Unit: milliseconds
                              # expr        min         lq       mean     median         uq        max neval
                         # f_989(ll)   84.67007   87.05084   87.50351   87.70766   88.25692   91.12715   100
                  # f_alistaire1(ll)   85.00209   87.35116   87.83935   87.91318   88.32242   98.69927   100
                         # f_d.b(ll)   85.15563   87.74943   88.01660   88.23258   88.72280   89.89943   100
             # f_G.Grothendieck1(ll)   85.38729   87.77707   88.40864   88.45328   89.03604  100.78963   100
             # f_G.Grothendieck3(ll)   85.85933   87.85805   88.69445   88.68118   89.28618  104.93881   100
             # f_G.Grothendieck4(ll) 1150.27718 1200.80601 1205.76164 1206.48442 1211.72250 1310.64802   100
                  # f_alistaire2(ll) 1178.14509 1202.61153 1207.05208 1205.89009 1211.49820 1325.72315   100
             # f_G.Grothendieck2(ll) 1177.02283 1204.55166 1210.40954 1208.95338 1213.82218 1278.82715   100
        

        【讨论】:

        • 对于少量数据,您的基准测试主要捕获管道的开销,如果您比较嵌套和管道的相同调用,例如 Gabor 的 1/3 和 2/4,您可以看到这一点。对足够大的数据进行基准测试以查看大规模差异会更有意义。
        • @alistaire 已更新。我没有包括您的第二个解决方案,因为它真的很耗时。
        • 有趣的是,组合矩阵的内存分配比多次调用colSums 更可怕。
        猜你喜欢
        • 1970-01-01
        • 2021-12-15
        • 2019-04-25
        • 1970-01-01
        • 1970-01-01
        • 2021-03-25
        • 1970-01-01
        • 2013-09-11
        • 1970-01-01
        相关资源
        最近更新 更多