gpt4 book ai didi

r - 为什么 sapply 缩放比具有样本大小的 for 循环慢?

转载 作者:行者123 更新时间:2023-12-04 18:06:20 27 4
gpt4 key购买 nike

所以假设我想取向量 X = 2*1:N 并将 e 提高到每个元素的指数。 (是的,我认为最好的方法是简单地通过向量化 exp(X),但重点是将 for 循环与 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')

我们得到以下结果。
N 与 t 的关系图:
enter image description here

log(N) 与 log(t) 的关系图
enter image description here

蓝色图是 for 循环方法,红色和绿色图是 sapply 方法。在常规图中,您可以看到,随着样本量变大,for 循环方法比 sapply 方法更受青睐,这完全不是我所期望的。如果您查看 log-log 图(为了更容易区分较小的 N 结果),我们会看到 sapply 的预期结果比小 N 的 for 循环更有效。

有人知道为什么 sapply 比具有样本大小的循环更慢吗?谢谢。

最佳答案

您没有考虑为结果向量分配空间所需的时间 Y1 .随着样本量的增加,分配Y1所需的时间成为执行时间的更大份额,而进行替换所需的时间成为更小的份额。
sapply始终为结果分配内存,因此这是随着样本大小增加效率降低的原因之一。 gagolews关于sapply还有一个很好的观点调用 simplify2array .这(可能)添加了另一个副本。

经过一些更多的测试,它看起来像 lapply随着对象变大,它仍然与包含 for 循环的字节编译函数大致相同或更慢。我不知道如何解释这一点,除了 do_lapply 中可能的这一行:

if (MAYBE_REFERENCED(tmp)) tmp = lazy_duplicate(tmp);

或者可能是如何 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')

关于r - 为什么 sapply 缩放比具有样本大小的 for 循环慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26430571/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com