如何加速 R for 循环?
how to speed up an R for loop?
我是 运行 R 中 GWmodel 包中 gwr.basic 函数的以下 for 循环。我需要做的是收集任何给定带宽的估计参数的平均值。
代码如下:
library(GWmodel)
data("DubVoter")
#Dub.voter
LARentMean = list()
for (i in 20:21)
{
gwr.res <- gwr.basic(GenEl2004 ~ DiffAdd + LARent + SC1 + Unempl + LowEduc + Age18_24 + Age25_44 + Age45_64, data = Dub.voter, bw = i, kernel = "bisquare", adaptive = TRUE, F123.test = TRUE)
a <- mean(gwr.res$SDF$LARent)
LARentMean[i] <- a
}
outcome = unlist(LARentMean)
> outcome
[1] -0.1117668 -0.1099969
但是返回结果的速度非常慢。我需要更广泛的范围,例如 20:200。有没有办法加快这个过程?如果不是,如何设置步进范围,比如 20 到 200,步长为 5,以减少操作次数?
我是 python R 的新用户。我在 SO 上读到,R 以 for 循环速度慢而闻名,并且有更有效的替代方案。欢迎在这一点上更加明确。
我的印象和@musically_ut一样。 for 循环和传统的 for-vs.apply
争论不太可能在这里帮助你。如果您有多个核心,请尝试进行并行化。有几个软件包,如 parallel
或 snowfall
。哪个包最终是最好和最快的取决于您的机器和操作系统。
这里最好并不总是最快的。跨平台工作的代码比额外的性能更有价值。透明度和易用性也可能超过最大速度。话虽这么说,我非常喜欢标准解决方案,并建议使用 parallel
,它随 R 一起提供并适用于 Windows、OSX 和 Linux。
编辑:这是使用 OP 示例的完全可重现的示例。
library(GWmodel)
data("DubVoter")
library(parallel)
bwlist <- list(bw1 = 20, bw2 = 21)
cl <- makeCluster(detectCores())
# load 'GWmodel' for each node
clusterEvalQ(cl, library(GWmodel))
# export data to each node
clusterExport(cl, varlist = c("bwlist","Dub.voter"))
out <- parLapply(cl, bwlist, function(e){
try(gwr.basic(GenEl2004 ~ DiffAdd + LARent + SC1 +
Unempl + LowEduc + Age18_24 + Age25_44 +
Age45_64, data = Dub.voter,
bw = e, kernel = "bisquare",
adaptive = TRUE, F123.test = TRUE ))
} )
LArent_l <- lapply(lapply(out,"[[","SDF"),"[[","LARent")
unlist(lapply(LArent_l,"mean"))
# finally, stop the cluster
stopCluster(cl)
除了按照 Matt Bannert 的建议使用并行化之外,您还应该预分配向量 LARentMean
。通常,并不是 for
循环本身很慢,而是 for
引诱您做一些缓慢的事情,例如创建增长向量。
考虑以下示例以了解增长向量与预分配内存相比的影响:
library(microbenchmark)
growing <- function(x) {
mylist <- list()
for (i in 1:x) {
mylist[[i]] <- i
}
}
allocate <- function(x) {
mylist <- vector(mode = "list", length = x)
for (i in 1:x) {
mylist[[i]] <- i
}
}
microbenchmark(growing(1000), allocate(1000), times = 1000)
# Unit: microseconds
# expr min lq mean median uq max neval
# growing(1000) 3055.134 4284.202 4743.4874 4433.024 4655.616 47977.236 1000
# allocate(1000) 867.703 917.738 998.0719 956.441 995.143 2564.192 1000
增长列表比预分配内存的版本慢大约 5 倍。
我是 运行 R 中 GWmodel 包中 gwr.basic 函数的以下 for 循环。我需要做的是收集任何给定带宽的估计参数的平均值。
代码如下:
library(GWmodel)
data("DubVoter")
#Dub.voter
LARentMean = list()
for (i in 20:21)
{
gwr.res <- gwr.basic(GenEl2004 ~ DiffAdd + LARent + SC1 + Unempl + LowEduc + Age18_24 + Age25_44 + Age45_64, data = Dub.voter, bw = i, kernel = "bisquare", adaptive = TRUE, F123.test = TRUE)
a <- mean(gwr.res$SDF$LARent)
LARentMean[i] <- a
}
outcome = unlist(LARentMean)
> outcome
[1] -0.1117668 -0.1099969
但是返回结果的速度非常慢。我需要更广泛的范围,例如 20:200。有没有办法加快这个过程?如果不是,如何设置步进范围,比如 20 到 200,步长为 5,以减少操作次数?
我是 python R 的新用户。我在 SO 上读到,R 以 for 循环速度慢而闻名,并且有更有效的替代方案。欢迎在这一点上更加明确。
我的印象和@musically_ut一样。 for 循环和传统的 for-vs.apply
争论不太可能在这里帮助你。如果您有多个核心,请尝试进行并行化。有几个软件包,如 parallel
或 snowfall
。哪个包最终是最好和最快的取决于您的机器和操作系统。
这里最好并不总是最快的。跨平台工作的代码比额外的性能更有价值。透明度和易用性也可能超过最大速度。话虽这么说,我非常喜欢标准解决方案,并建议使用 parallel
,它随 R 一起提供并适用于 Windows、OSX 和 Linux。
编辑:这是使用 OP 示例的完全可重现的示例。
library(GWmodel)
data("DubVoter")
library(parallel)
bwlist <- list(bw1 = 20, bw2 = 21)
cl <- makeCluster(detectCores())
# load 'GWmodel' for each node
clusterEvalQ(cl, library(GWmodel))
# export data to each node
clusterExport(cl, varlist = c("bwlist","Dub.voter"))
out <- parLapply(cl, bwlist, function(e){
try(gwr.basic(GenEl2004 ~ DiffAdd + LARent + SC1 +
Unempl + LowEduc + Age18_24 + Age25_44 +
Age45_64, data = Dub.voter,
bw = e, kernel = "bisquare",
adaptive = TRUE, F123.test = TRUE ))
} )
LArent_l <- lapply(lapply(out,"[[","SDF"),"[[","LARent")
unlist(lapply(LArent_l,"mean"))
# finally, stop the cluster
stopCluster(cl)
除了按照 Matt Bannert 的建议使用并行化之外,您还应该预分配向量 LARentMean
。通常,并不是 for
循环本身很慢,而是 for
引诱您做一些缓慢的事情,例如创建增长向量。
考虑以下示例以了解增长向量与预分配内存相比的影响:
library(microbenchmark)
growing <- function(x) {
mylist <- list()
for (i in 1:x) {
mylist[[i]] <- i
}
}
allocate <- function(x) {
mylist <- vector(mode = "list", length = x)
for (i in 1:x) {
mylist[[i]] <- i
}
}
microbenchmark(growing(1000), allocate(1000), times = 1000)
# Unit: microseconds
# expr min lq mean median uq max neval
# growing(1000) 3055.134 4284.202 4743.4874 4433.024 4655.616 47977.236 1000
# allocate(1000) 867.703 917.738 998.0719 956.441 995.143 2564.192 1000
增长列表比预分配内存的版本慢大约 5 倍。