前報は,行列あるいはデータフレームの列方向の計算であった。
今回は,行方向の計算について検討する。
データ規模はやや大きい 50000×1000 を対象とした。
library(microbenchmark)
set.seed(777)
nr = 50000
nc = 1000
x = matrix(runif(nr * nc), nr, nc)
df = as.data.frame(x)
cpu = microbenchmark(
Reduce.df = Reduce("+", df),
rowSums.df = rowSums(df),
apply.df = apply(df, 1, sum),
for.loop.df = {
m1 = numeric(nr)
for (i in 1:nc) {
m1 = m1 + df[, i]
}
m1
},
rowSums.mat = rowSums(x),
apply.mat = apply(x, 1, sum),
for.loop.mat = {
M1 = numeric(nr)
for (i in 1:nc) {
M1 = M1 + x[, i]
}
M1
},
unit="ms"
)
par(mar=c(2.7, 6.0, 0.5, 0.5), mgp=c(1.0, 0.5, 0), tcl=-0.2)
plot(cpu,
col=rep(c("blue", "red"), c(4, 3)),
las=1, horizontal=TRUE, log = "x",
xlab="", ylab=""
)
mtext("cpu time in nanoseconds", 1, 1.5)
Unit: milliseconds
expr min lq mean median uq max neval cld
Reduce.df 186.39777 202.03146 243.48758 224.28278 280.4589 455.4433 100 b
rowSums.df 335.91715 359.85339 412.49965 409.48675 433.2498 686.4874 100 c
apply.df 1804.48749 1971.52982 2147.20970 2092.33050 2304.0389 3154.3865 100 f
for.loop.df 204.47810 220.42069 274.09268 243.64281 308.5390 510.1865 100 b
rowSums.mat 88.33803 89.95369 99.45286 98.05859 108.2877 118.9649 100 a
apply.mat 1140.83549 1247.81805 1347.21777 1329.95254 1420.0599 1938.3013 100 e
for.loop.mat 387.88910 420.76785 498.32962 498.12949 550.1991 880.5908 100 d
所見
1. 行列を対象とした rowSums がもっとも速い。for loop は遅いが, apply は相当遅い。
2. データフレームの場合は Reduce と for loop が同程度速く,rowSums は少し遅い。apply はとてつもなく遅い。
なお,行列を対象とする for loop の場合であるが,以下の 2 通りの書き方では M1 = M1 + x[, i] のほうが3倍ほど速いのに注目すべきである。(データフレームの場合も同じ)
理由は,計算中のメモリーアクセスが M1 = M1 + x[, i] は列方向でメモリー上で連続しているのに対し,M1[i] = sum(x[i, ]) は行方向のアクセスで,飛び飛びのメモリーを参照するためである。
system.time({ # 0.277sec.
M1 = numeric(nr)
for (i in 1:nc) {
M1 = M1 + x[, i] # ベクトル演算
}
})
system.time({ # 0.825sec.
M1 = numeric(nr)
for (i in 1:nr) {
M1[i] = sum(x[i, ]) # 関数の結果を要素に代入
}
})
system.time({ # 0.140sec.
m1 = numeric(nr)
for (i in 1:nc) {
m1 = m1 + df[, i] # ベクトル演算
}
})
system.time({ # 0.875sec.
m1 = numeric(nr)
for (i in 1:nr) {
m1[i] = sum(x[i, ]) # 関数の結果を要素に代入
}
})
※コメント投稿者のブログIDはブログ作成者のみに通知されます