4

我正在为 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,以减少操作次数?

我是 R 的新手。我在 SO 上读到 R 以 for 循环速度慢而闻名,并且有更有效的替代方案。欢迎对这一点进行更明确的说明。

4

2 回答 2

4

除了像 Matt Bannert 建议的那样使用并行化之外,您还应该预先分配 vector 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 倍。

于 2015-08-22T15:32:44.087 回答
4

我得到了和@musically_ut 一样的印象。for 循环和传统的for-vs.apply辩论在这里不太可能对您有所帮助。如果您有多个内核,请尝试进行并行化。有几个包,如parallelor snowfall。最终哪个软件包最好和最快取决于您的机器和操作系统。

最好在这里并不总是等于最快。一个跨平台工作的代码,它的价值不仅仅是一点额外的性能。透明度和易用性也可以超过最大速度。话虽如此,我非常喜欢标准解决方案,并建议使用parallelR 附带的并且适用于 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)
于 2015-08-22T15:02:40.690 回答