使用R parallel来加速bootstrap

时间:2013-04-12 18:26:02

标签: r parallel-processing statistics-bootstrap

我想加快我的自举功能,这本身就很好用。我读过,因为R 2.14有一个名为parallel的包,但我觉得这对某人来说很难。对计算机科学知识不足以真正实现它。也许有人可以提供帮助。

所以我们这里有一个引导程序:

n<-1000
boot<-1000
x<-rnorm(n,0,1)
y<-rnorm(n,1+2*x,2)
data<-data.frame(x,y)
boot_b<-numeric()
for(i in 1:boot){
  bootstrap_data<-data[sample(nrow(data),nrow(data),replace=T),]
  boot_b[i]<-lm(y~x,bootstrap_data)$coef[2]
  print(paste('Run',i,sep=" "))
}

目标是使用并行处理/利用我的PC的多个核心。我正在Windows下运行R.谢谢!

编辑(经诺亚回复后)

以下语法可用于测试:

library(foreach)
library(parallel)
library(doParallel)
registerDoParallel(cores=detectCores(all.tests=TRUE))
n<-1000
boot<-1000
x<-rnorm(n,0,1)
y<-rnorm(n,1+2*x,2)
data<-data.frame(x,y)
start1<-Sys.time()
boot_b <- foreach(i=1:boot, .combine=c) %dopar% {
  bootstrap_data<-data[sample(nrow(data),nrow(data),replace=T),]
  unname(lm(y~x,bootstrap_data)$coef[2])
}
end1<-Sys.time()
boot_b<-numeric()
start2<-Sys.time()
for(i in 1:boot){
  bootstrap_data<-data[sample(nrow(data),nrow(data),replace=T),]
  boot_b[i]<-lm(y~x,bootstrap_data)$coef[2]
}
end2<-Sys.time()
start1-end1
start2-end2
as.numeric(start1-end1)/as.numeric(start2-end2)

然而,在我的机器上,简单的R代码更快。这是并行处理的已知副作用之一,即它会导致开销过程,从而增加了像这样的“简单任务”中的时间吗?

编辑:在我的机器上,parallel代码比“简单”代码长约5倍。当我增加任务的复杂性时(例如,增加bootn),这个因素显然不会改变。那么代码或我的机器可能存在问题(基于Windows的处理?)。

3 个答案:

答案 0 :(得分:8)

试用boot套餐。它经过了优化,并包含parallel参数。这个软件包的棘手之处在于你必须编写新的函数来计算你的统计数据,它接受你正在处理的数据和一个索引向量来重新采样数据。因此,从您定义data的位置开始,您可以执行以下操作:

# Define a function to resample the data set from a vector of indices
# and return the slope
slopeFun <- function(df, i) {
  #df must be a data frame.
  #i is the vector of row indices that boot will pass
  xResamp <- df[i, ]
  slope <- lm(y ~ x, data=xResamp)$coef[2] 
} 

# Then carry out the resampling
b <- boot(data, slopeFun, R=1000, parallel="multicore")

b$t是重新采样统计信息的向量,boot有很多很好的方法可以轻松地处理它 - 例如plot(b)

请注意,并行方法取决于您的平台。在Windows计算机上,您需要使用parallel="snow"

答案 1 :(得分:7)

我没有在Windows上使用foreach后端测试parallel,但我相信这对您有用:

library(foreach)
library(doSNOW)

cl <- makeCluster(c("localhost","localhost"), type = "SOCK")
registerDoSNOW(cl=cl)

n<-1000
boot<-1000
x<-rnorm(n,0,1)
y<-rnorm(n,1+2*x,2)
data<-data.frame(x,y)
boot_b <- foreach(i=1:boot, .combine=c) %dopar% {
  bootstrap_data<-data[sample(nrow(data),nrow(data),replace=T),]
  unname(lm(y~x,bootstrap_data)$coef[2])
}

答案 2 :(得分:3)

我认为主要的问题是你有很多小任务。在某些情况下,您可以通过使用任务分块来提高性能,这会导致主服务器和工作服务器之间的数据传输更少但更大,这通常更有效:

boot_b <- foreach(b=idiv(boot, chunks=getDoParWorkers()), .combine='c') %dopar% {
  sapply(1:b, function(i) {
    bdata <- data[sample(nrow(data), nrow(data), replace=T),]
    lm(y~x, bdata)$coef[[2]]
  })
}

我喜欢使用idiv功能,但如果您愿意,可以b=rep(boot/detectCores(),detectCores())