複数の行列の足し算をしたいです。 行列が2つであれば、行列A+行列Bで済みます。たくさんあってもこの方法でいいですが、気持ち悪いです。なにより大変です。 ということでいくつか考えたメモです。
# 複数の行列をリストで持つオブジェクトを作ります
set.seed(123)
N <- 100
m <- vector('list', N)
for(i in 1:N) m[[i]] <- matrix(rnorm(6), 2, 3)
4つ考えました。
# for文で1つずつ足す。感覚的
for_loop <- function(data) {
res <- data[[1]]
for(i in 2:length(data)) {
res <- res + data[[i]]
}
res
}
for_loop(m)
## [,1] [,2] [,3]
## [1,] 10.581840 14.80878 4.219499
## [2,] -8.820872 -10.11387 2.389854
# 行列を1行にして足し、形を戻す
vec_sum <- function(data) {
matrix(rowSums(sapply(data, as.vector)), nrow = nrow(data[[1]]), ncol = ncol(data[[1]]))
}
vec_sum(m)
## [,1] [,2] [,3]
## [1,] 10.581840 14.80878 4.219499
## [2,] -8.820872 -10.11387 2.389854
# リストから3次元のarray形式としてapplyをかける
array_sum <- function(data) {
data2 <- array(dim = c(nrow(data[[1]]), ncol(data[[1]]), length(data)))
for(i in 1:length(data)) {
data2[, , i] <- data[[i]]
}
apply(data2, 1:2, sum)
}
array_sum(m)
## [,1] [,2] [,3]
## [1,] 10.581840 14.80878 4.219499
## [2,] -8.820872 -10.11387 2.389854
# Reduceで一発。気持ちいい
reduce <- function(data) {
Reduce('+', data)
}
reduce(m)
## [,1] [,2] [,3]
## [1,] 10.581840 14.80878 4.219499
## [2,] -8.820872 -10.11387 2.389854
一応速さでも測りましょう
require(rbenchmark)
## Loading required package: rbenchmark
benchmark(replications = 10^5, for_loop(m), vec_sum(m), array_sum(m), reduce(m))
## test replications elapsed relative user.self sys.self user.child
## 3 array_sum(m) 100000 31.284 2.861 30.410 0.098 0
## 1 for_loop(m) 100000 11.616 1.062 11.369 0.048 0
## 4 reduce(m) 100000 10.936 1.000 10.722 0.041 0
## 2 vec_sum(m) 100000 28.009 2.561 27.307 0.127 0
## sys.child
## 3 0
## 1 0
## 4 0
## 2 0
コードとしてはReduceを使うのが気持ちいいですが、たいして遅くもないのでやっぱりfor文がわかりやすくて良さそうです。