<- 10000
n <- 5
m <- m - 1 dof
ベクトル化
performance
table
ループ回避して高速化する
5つの乱数を2組生成して、分散と共分散を多数計算する。
for
ループで書いたが、n
が大きくなると遅くなる。
set.seed(514)
<- Sys.time()
start
for (i in 1:n) {
<- scale(rnorm(m), scale = FALSE)
x <- var(x)
xx <- scale(rnorm(m), scale = FALSE)
y <- cov(x, y)
yx
}<- Sys.time() - start t.loop
apply
を使ってループを回避したが、全く速くならず、むしろ遅くなる。 n=1000000
のように大きくなると、cov()
の計算が原因でメモリ(ヒープ)が不足する。 種は固定しているが、rnorm()
の呼び出しの順番が異なるので同一の結果にはならない。
set.seed(514)
<- Sys.time()
start
<- matrix(rnorm(m * n), nrow = m) |>
x apply(2, scale, scale = FALSE)
<- matrix(rnorm(m * n), nrow = m) |>
y apply(2, scale, scale = FALSE)
<- apply(x, 2, var)
Pb <- diag(cov(x, y))
yx #yx <- numeric(n)
#for (i in 1:n) {
# yx[i] <- cov(Xb[, i], y[, i])
#}
<- Sys.time() - start t.apply
scale()
にはmatrix
を与えることができ、列に対する正規化を行う。 分散は偏差平方平均、共分散は偏差の積の平均なので、要素積をして平均する。 apply(x^2, 2, mean)
やapply(x * y, 2, mean)
よりもcolMeans()
の方が速い。 平均は標本数で割るので、係数を調整する。
set.seed(514)
<- Sys.time()
start
<- scale(matrix(rnorm(m * n), nrow = m), scale = FALSE)
x <- scale(matrix(rnorm(m * n), nrow = m), scale = FALSE)
y <- colMeans(x^2) * m / dof
v <- colMeans(x * y) * m / dof
yx
<- Sys.time() - start t.vec
tinytable
で表にします。
library(tinytable)
<- c("loop", "apply", "vec")
code <- as.numeric(c(t.loop, t.apply, t.vec))
time <- as.numeric(t.loop) / time
speedup <- data.frame(code, time, speedup)
df tt(df, digits = 2, align = "d")
code | time | speedup |
---|---|---|
loop | 0.543 | 1 |
apply | 1.008 | 0.54 |
vec | 0.004 | 135.1 |