Home > database >  element-wise averages of two (or more) nested lists of matrices
element-wise averages of two (or more) nested lists of matrices

Time:04-15

I have two lists A_1 and A_2, each contains two matrices.

A_1 <- list(a=matrix(1:8, 2), b=matrix(2:9, 2))

A_2 <- list(a=matrix(10:17, 2), b=matrix(5:12, 2))

I'd like to calculate element-wise averages of these two lists which results a list of

tibble::lst((A_1$a   A_2$a)/2, (A_1$b   A_2$b)/2)

I used

purrr::pmap(list(A_1 , A_2), mean)

but got

Error in mean.default(.l[[1L]][[i]], .l[[2L]][[i]], ...) : 
  'trim' must be numeric of length one`  

or

purrr::map2(A_1, A_2, mean)

Error in mean.default(.x[[i]], .y[[i]], ...) : 
  'trim' must be numeric of length one`

CodePudding user response:

In base R, We could use:

A <-list(A_1, A_2)
lapply(Reduce(\(x, y)Map(' ', x, y), A), '/', length(A))

$a
     [,1] [,2] [,3] [,4]
[1,]  5.5  7.5  9.5 11.5
[2,]  6.5  8.5 10.5 12.5

$b
     [,1] [,2] [,3] [,4]
[1,]  3.5  5.5  7.5  9.5
[2,]  4.5  6.5  8.5 10.5

This code is generic in that we can use to find the mean of several lists. Note that A_1 and A_2 must have the same number of matrices, not necessarily 2. Can be 10 etc. Also note that each corresponding matrix has the same dimensions. Example below:

B_1 <- list(matrix(c(1,2,3,4), 2), matrix(c(1,3,4,2), 2),
            matrix(c(1:10), 5), matrix(c(1:20), 5))
B_2 <- lapply(B_1, '*', 2) # In this case, its B_1 * 2
B_3 <- lapply(B_2, '*', 3) #

Now you could use the code provide above:

B <-list(B_1, B_2, B_3)
lapply(Reduce(\(x, y)Map(' ', x, y), B), '/', length(B))

CodePudding user response:

Your mistake is in using the second matrix as trim= argument of mean whcih is the second. You need to concatenate the matrices. Example:

mean(1:3, 2:4)
# Error in mean.default(1:3, 2:4) : 'trim' must be numeric of length one

mean(c(1:3, 2:4))
# [1] 2.5

As solution you may use Map

Map(\(x, y) (x   y)/2, A_1, A_2)
# $a
#      [,1] [,2] [,3] [,4]
# [1,]  5.5  7.5  9.5 11.5
# [2,]  6.5  8.5 10.5 12.5
# 
# $b
#      [,1] [,2] [,3] [,4]
# [1,]  3.5  5.5  7.5  9.5
# [2,]  4.5  6.5  8.5 10.5

Or, why not using arrays?

AA_1 <- array(unlist(A_1), dim=c(dim(A_1$a), length(A_1)))
AA_2 <- array(unlist(A_2), dim=c(dim(A_2$a), length(A_2)))

(AA_1   AA_2)/2
# , , 1
# 
#      [,1] [,2] [,3] [,4]
# [1,]  5.5  7.5  9.5 11.5
# [2,]  6.5  8.5 10.5 12.5
# 
# , , 2
# 
#      [,1] [,2] [,3] [,4]
# [1,]  3.5  5.5  7.5  9.5
# [2,]  4.5  6.5  8.5 10.5

CodePudding user response:

in base R:

item_names  <- names(A_1)

structure(
    lapply(item_names, function(name){
        0.5 * (A_1[[name]]   A_2[[name]])
        ## or, if you want the scalar mean:
        ## mean(A_1[[name]]   A_2[[name]])
    }),
    names = item_names
)


#> $a
#>      [,1] [,2] [,3] [,4]
#> [1,]  5.5  7.5  9.5 11.5
#> [2,]  6.5  8.5 10.5 12.5
#> 
#> $b
#>      [,1] [,2] [,3] [,4]
#> [1,]  3.5  5.5  7.5  9.5
#> [2,]  4.5  6.5  8.5 10.5

  • Related