所以假设我想取向量X = 2*1:N并将e提高到每个元素的指数.(是的,我认识到这样做的最好方法是简单地通过向量化exp(X),但重点是将循环与sapply进行比较).好吧,我通过逐步尝试三个方法(一个用于for循环,两个用不同的方式应用了sapply)和不同的样本大小并测量相应的时间来测试.然后,我绘制每种方法的样本大小N对时间t.
每种方法用"#####"表示.
k <- 20
t1 <- rep(0,k)
t2 <- rep(0,k)
t3 <- rep(0,k)
L <- round(10^seq(4,7,length=k))
for (i in 1:k) {
X <- 2*1:L[i]
Y1 <- rep(0,L[i])
t <- system.time(for (j in 1:L[i]) Y1[j] <- exp(X[j]))[3] #####
t1[i] <- t
}
for (i in 1:k) {
X <- 2*1:L[i]
t <- system.time( Y2 <- sapply(1:L[i], function(q) exp(X[q])) )[3] #####
t2[i] <- t
}
for (i in 1:k) {
X <- 2*1:L[i]
t <- system.time( Y3 <- sapply(X, function(x) exp(x)) )[3] #####
t3[i] <- t
}
plot(L, t3, type='l', col='green')
lines(L, t2,col='red')
lines(L, t1,col='blue')
plot(log(L), log(t1), type='l', col='blue')
lines(log(L), log(t2),col='red')
lines(log(L), log(t3), col='green')
Run Code Online (Sandbox Code Playgroud)
我们得到以下结果.N vs t的情节:

log(N)vs log(t)的图

蓝色图是for循环方法,红色和绿色图是sapply方法.在常规图中,您可以看到,随着样本大小变大,for循环方法比sapply方法更受青睐,这根本不是我所期望的.如果你看一下log-log图(为了更容易区分较小的N结果),我们看到sapply的预期结果比小N的循环更有效.
有没有人知道为什么sapply比样本大小的循环更慢?谢谢.
您没有考虑为结果向量分配空间所需的时间Y1。随着样本大小的增加,分配所花费的时间Y1在执行时间中所占的份额变得更大,而替换所花费的时间所占的份额变得更小。
sapply总是为结果分配内存,因此这就是随着样本大小的增加而效率降低的原因之一。gagolewssapply对于调用也有一个很好的观点simplify2array。这(可能)会添加另一个副本。
经过更多测试后,随着lapply对象变大,它看起来仍然与包含 for 循环的字节编译函数大致相同或更慢。我不知道如何解释这一点,除了可能的这一行do_lapply:
if (MAYBE_REFERENCED(tmp)) tmp = lazy_duplicate(tmp);
Run Code Online (Sandbox Code Playgroud)
或者可能是如何lapply构造函数调用的东西......但我主要是猜测。
这是我用来测试的代码:
k <- 20
t1 <- rep(0,k)
t2 <- rep(0,k)
t3 <- rep(0,k)
L <- round(10^seq(4,7,length=k))
L <- round(10^seq(4,6,length=k))
# put the loop in a function
fun <- function(X, L) {
Y1 <- rep(0,L)
for (j in 1:L)
Y1[j] <- exp(X[j])
Y1
}
# for loops often benefit from compiling
library(compiler)
cfun <- cmpfun(fun)
for (i in 1:k) {
X <- 2*1:L[i]
t1[i] <- system.time( Y1 <- fun(X, L[i]) )[3]
}
for (i in 1:k) {
X <- 2*1:L[i]
t2[i] <- system.time( Y2 <- cfun(X, L[i]) )[3]
}
for (i in 1:k) {
X <- 2*1:L[i]
t3[i] <- system.time( Y3 <- lapply(X, exp) )[3]
}
identical(Y1, Y2) # TRUE
identical(Y1, unlist(Y3)) # TRUE
plot(L, t1, type='l', col='blue', log="xy", ylim=range(t1,t2,t3))
lines(L, t2, col='red')
lines(L, t3, col='green')
Run Code Online (Sandbox Code Playgroud)