upabove
upabove

Reputation: 1119

Mean of each element of a list of matrices

I have a list with three matrixes:

a<-matrix(runif(100))
b<-matrix(runif(100))
c<-matrix(runif(100))

mylist<-list(a,b,c)

I would like to obtain the mean of each element in the three matrices.

I tried: aaply(laply(mylist, as.matrix), c(1, 1), mean) but this returns the means of each matrix instead of taking the mean of each element as rowMeans() would.

Upvotes: 5

Views: 3804

Answers (4)

CoderGuy123
CoderGuy123

Reputation: 6649

The other answers fail when there's partial missing data. There is probably some faster way to handle this issue, but we can also just loop across each cell.

average_cells = function(m1, m2) {
  #assert even sizes
  stopifnot(all(dim(m1) == dim(m2)))
  
  #matrix for results
  res = matrix(NA_real_, nrow = nrow(m1), ncol = ncol(m1))
  
  #loop over rows and cols
  for (row in 1:nrow(m1)) {
    for (col  in 1:ncol(m1)) {
      res[row, col] = mean(c(m1[row, col], m2[row, col]), na.rm = T)
    }
  }
  
  res
}

#show it works
average_cells(
  matrix(1:9, nrow = 3),
  matrix(rep(0, 9), nrow = 3)
)
#>      [,1] [,2] [,3]
#> [1,]  0.5  2.0  3.5
#> [2,]  1.0  2.5  4.0
#> [3,]  1.5  3.0  4.5

average_cells(
  matrix(1:9, nrow = 3),
  matrix(rep(NA, 9), nrow = 3)
)
#>      [,1] [,2] [,3]
#> [1,]    1    4    7
#> [2,]    2    5    8
#> [3,]    3    6    9
Created on 2024-05-18 with reprex v2.1.0

Upvotes: 0

nisetama
nisetama

Reputation: 8863

The simplify2array option is really slow because it calls the mean function nrow*ncol times:

Unit: milliseconds
           expr         min          lq       mean     median         uq        max neval
         reduce    7.320327    8.051267   11.23352   12.17859   13.59846   13.72176    10
 simplify2array 4233.090223 4674.827077 4802.74033 4808.00417 5010.75771 5228.05362    10
     via_vector   27.720372   42.757517   51.95250   59.47917   60.11251   61.83605    10
       for_loop   10.405315   12.919731   13.93157   14.46218   15.82175   15.89977    10
l=lapply(1:3,function(i)matrix(i*(1:1e6),10))

microbenchmark(times=10,
  Reduce={Reduce(`+`,l)/length(l)},
  simplify2array={apply(simplify2array(l),c(1,2),mean)},
  via_vector={matrix(rowMeans(sapply(l,as.numeric)),nrow(l[[1]]))},
  for_loop={o=l[[1]];for(i in 2:length(l))o=o+l[[i]];o/length(l)}
)

Upvotes: 0

Ferdinand.kraft
Ferdinand.kraft

Reputation: 12819

Your question is not clear.

For the mean of all elements of each matrix:

sapply(mylist, mean)

For the mean of every row of each matrix:

sapply(mylist, rowMeans)

For the mean of every column of each matrix:

sapply(mylist, colMeans)

Note that sapply will automatically simplify the results to a vector or matrix, if possible. In the first case, the result will be a vector, but in the second and third, it may be a list or matrix.

Example:

a <- matrix(1:6,2,3)
b <- matrix(7:10,2,2)
c <- matrix(11:16,3,2)
mylist <- list(a,b,c)

> mylist
[[1]]
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

[[2]]
     [,1] [,2]
[1,]    7    9
[2,]    8   10

[[3]]
     [,1] [,2]
[1,]   11   14
[2,]   12   15
[3,]   13   16

Results:

> sapply(mylist, mean)
[1]  3.5  8.5 13.5

> sapply(mylist, rowMeans)
[[1]]
[1] 3 4

[[2]]
[1] 8 9

[[3]]
[1] 12.5 13.5 14.5

> sapply(mylist, colMeans)
[[1]]
[1] 1.5 3.5 5.5

[[2]]
[1] 7.5 9.5

[[3]]
[1] 12 15

Upvotes: -1

Jilber Urbina
Jilber Urbina

Reputation: 61154

Maybe what you want is:

> set.seed(1)
> a<-matrix(runif(4)) 
> b<-matrix(runif(4))
> c<-matrix(runif(4))
> mylist<-list(a,b,c)  # a list of 3 matrices 
> 
> apply(simplify2array(mylist), c(1,2), mean)
          [,1]
[1,] 0.3654349
[2,] 0.4441000
[3,] 0.5745011
[4,] 0.5818541

The vector c(1,2) for MARGIN in the apply call indicates that the function mean should be applied to rows and columns (both at once), see ?apply for further details.

Another alternative is using Reduce function

> Reduce("+", mylist)/ length(mylist)
          [,1]
[1,] 0.3654349
[2,] 0.4441000
[3,] 0.5745011
[4,] 0.5818541

Upvotes: 18

Related Questions