Reputation: 1119
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
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
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
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
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