简体   繁体   中英

Summing consecutive matrices in nested list r

I have a list of 2x2 matrices that look something like this:

matlist=
  list(structure(list(`1` = structure(c(8, 16, 3, 13), .Dim = c(2L, 2L)),
                    `2` = structure(c(6, 3, 0, 6), .Dim = c(2L, 2L)), 
                    `3` = structure(c(39,55, 15, 11), .Dim = c(2L, 2L)), 
                    `4` = structure(c(46, 53, 18,5), .Dim = c(2L, 2L)), 
                    `5` = structure(c(14, 6, 1, 12), .Dim = c(2L,2L)), 
                    `6` = structure(c(20, 6, 0, 12), .Dim = c(2L, 2L)), 
                    `7` = structure(c(4, 1, 0, 4), .Dim = c(2L, 2L))), 
                    .Names = c("1","2", "3", "4", "5", "6", "7" )), 
     structure(list(`1` = structure(c(38, 58, 0, 23), .Dim = c(2L, 2L)), 
                    `2` = structure(c(13, 10, 0, 7), .Dim = c(2L, 2L)), 
                    `3` = structure(c(22, 19, 1, 10), .Dim = c(2L,2L)), 
                    `4` = structure(c(8, 7, 0, 4), .Dim = c(2L, 2L)), 
                    `5` = structure(c(12,13, 3, 3), .Dim = c(2L, 2L)), 
                    `6` = structure(c(10, 8, 2, 2), .Dim = c(2L,2L)), 
                    `7` = structure(c(15, 14, 5, 5), .Dim = c(2L, 2L))), 
                    .Names = c("1", "2", "3", "4", "5", "6", "7"))
     )

This looks like this:

lapply(matlist, head,4)

[[1]]
[[1]]$`1`
     [,1] [,2]
[1,]    8    3
[2,]   16   13

[[1]]$`2`
     [,1] [,2]
[1,]    6    0
[2,]    3    6

[[1]]$`3`
     [,1] [,2]
[1,]   39   15
[2,]   55   11

[[1]]$`4`
     [,1] [,2]
[1,]   46   18
[2,]   53    5


[[2]]
[[2]]$`1`
     [,1] [,2]
[1,]   38    0
[2,]   58   23

[[2]]$`2`
     [,1] [,2]
[1,]   13    0
[2,]   10    7

[[2]]$`3`
     [,1] [,2]
[1,]   22    1
[2,]   19   10

[[2]]$`4`
     [,1] [,2]
[1,]    8    0
[2,]    7    4

What I want to do is to sum every two consecutive matrices within each element. Therefore I want to sum the 1st and 2nd matrices, the 2nd and 3rd, the 3rd and 4th maticres.... all the way until the last two matrices of '1'. I want to do the same for all the matrices in '2'.... and so on for all the nested lists in the larger list.

I can sum all matrices in a list using base:

lapply(matlist, function(x) Reduce('+', x))

or as I prefer using purrr (as this is going to fit into a long chain of syntax):

library(purrr)
matlist %>% map(~ Reduce('+', .))

[[1]]
     [,1] [,2]
[1,]  137   37
[2,]  140   63

[[2]]
     [,1] [,2]
[1,]  118   11
[2,]  129   54

How to do this for every 2 consecutive matrices within each sub-list without resorting to loops - ideally I'd have a vectorized solution?

Example of desired output for first two summations of sub-list 1:

 matlist[[1]][[1]]+matlist[[1]][[2]]
     [,1] [,2]
[1,]   14    3
[2,]   19   19

 matlist[[1]][[2]]+matlist[[1]][[3]]
     [,1] [,2]
[1,]   45   15
[2,]   58   17

This seems to work:

res = lapply(matlist, function(x) Map(`+`, head(x,-1), tail(x,-1)))

# sample of the result:
res[[1]][1:2]
# $`1`
#      [,1] [,2]
# [1,]   14    3
# [2,]   19   19
# 
# $`2`
#      [,1] [,2]
# [1,]   45   15
# [2,]   58   17

While I like @Frank's solution for its readability, I want to add another approach. You could vectorize the Map or mapply call if you convert your nested list matrices into a list of arrays:

set.seed(123)
matlist <- replicate(100,
                     replicate(100, matrix(sample(4), nrow=2),
                               simplify=FALSE),
                     simplify=FALSE)

.array <- function(x) {
  a <- lapply(x, function(xx)array(unlist(xx), dim=c(2, 2, length(xx))))
  lapply(a, function(aa)aa[,,-dim(aa)[3]]+aa[,,-1])
}

frank <- function(x) {
  lapply(x, function(xx) Map(`+`, head(xx,-1), tail(xx,-1)))
}

library("rbenchmark")
benchmark(frank(matlist), .array(matlist), order = "relative",
          columns = c("test", "replications", "elapsed", "relative"))
#             test replications elapsed relative
#2 .array(matlist)          100   0.460    1.000
#1  frank(matlist)          100   2.386    5.187

Maybe it is worth to change your data structure to an array instead of a nested list of matrices.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM