在 R 中拆分向量以进行并行采样时输出维度错误
wrong output dimensions when splitting a vector for parallel sampling in R
在 Windows 中(尚未在 Linux 中进行测试),我正在尝试(令人尴尬地)对大量人口进行贝叶斯抽样并行化。我正在 运行 进行一些测试,发现在处理列表的对象长度不同的列表时有一些非常令人担忧的行为。使用的库是 parallel
、snow
、doSNOW
、foreach
和 rlecuyer
。
## Set parameters
cores<-4; N<-10004; Mean<-rnorm(N,sd=0.7); SD<-rnorm(N,mean=1,sd=0.1)
## Split the population
lst<-suppressWarnings(split(1:N,f=1:cores))
## Initialize cluster
cl <<- parallel::makePSOCKcluster(cores)
parallel::clusterSetRNGStream(cl, iseed = round(runif(cores)*1001))
## Export and run test
clusterExport(cl,c("lst"))
system.time(
theta<-as.vector(parSapply(cl,1:cores,function(x) rnorm(length(lst[[x]]),mean=Mean[lst[[x]]],sd=SD)))
)
## validate length
system.time(
n.lst<-as.vector(parSapply(cl,1:cores,function(x) lst[[x]]))
)
## Stop the cluster and check data
parallel::stopCluster(cl)
length(theta) # 10004
length(n.lst) # 10004
现在我将人口更改为不能被 4 整除的数字
## Set parameters
cores<-4; N<-10001; Mean<-rnorm(N,sd=0.7); SD<-rnorm(N,mean=1,sd=0.1)
## Run the same code above... And check the output arrays:
length(theta) # 25010000
length(n.lst) # 25010000
所以是的,列表呈指数级增长...到数组的长度不是 2500+2500+2500+2501,而是 2500*2501*4...这对我来说毫无意义.
原来问题出在parSapply
的使用上;我不得不将问题转换为使用 parLapply
,我终于得到了一些可以接受的结果。当按照以下方式重新编码问题时,一切都解决了。注意:我不得不远离 split
因为没有明显的方法可以防止它 运行 它拆分的索引上的模数。相反,我创建了一个按顺序拆分向量的函数。
vsplit<-function(x,f) {
setNames(lapply(f,function (y) x[ceiling((1:length(x))/(length(x)/max(f)))==y]),f)
}
PNorm<-function(x) {
rnorm(length(lt[[x]]),lt[[x]],1)
}
settings<-list(); cores<-settings$cores<-4; N<-10000001
Mean<-rnorm(N,sd=0.7)
SD<-1
lt<-suppressWarnings(vsplit(Mean,1:cores))
cl <<- parallel::makePSOCKcluster(settings$cores)
parallel::clusterSetRNGStream(cl, iseed = round(runif(settings$cores)*1001))
clusterExport(cl,c("lt"))
system.time(
that<-unlist(parLapply(cl,1:cores,PNorm))
)
length(that)
parallel::stopCluster(cl)
在 Windows 中(尚未在 Linux 中进行测试),我正在尝试(令人尴尬地)对大量人口进行贝叶斯抽样并行化。我正在 运行 进行一些测试,发现在处理列表的对象长度不同的列表时有一些非常令人担忧的行为。使用的库是 parallel
、snow
、doSNOW
、foreach
和 rlecuyer
。
## Set parameters
cores<-4; N<-10004; Mean<-rnorm(N,sd=0.7); SD<-rnorm(N,mean=1,sd=0.1)
## Split the population
lst<-suppressWarnings(split(1:N,f=1:cores))
## Initialize cluster
cl <<- parallel::makePSOCKcluster(cores)
parallel::clusterSetRNGStream(cl, iseed = round(runif(cores)*1001))
## Export and run test
clusterExport(cl,c("lst"))
system.time(
theta<-as.vector(parSapply(cl,1:cores,function(x) rnorm(length(lst[[x]]),mean=Mean[lst[[x]]],sd=SD)))
)
## validate length
system.time(
n.lst<-as.vector(parSapply(cl,1:cores,function(x) lst[[x]]))
)
## Stop the cluster and check data
parallel::stopCluster(cl)
length(theta) # 10004
length(n.lst) # 10004
现在我将人口更改为不能被 4 整除的数字
## Set parameters
cores<-4; N<-10001; Mean<-rnorm(N,sd=0.7); SD<-rnorm(N,mean=1,sd=0.1)
## Run the same code above... And check the output arrays:
length(theta) # 25010000
length(n.lst) # 25010000
所以是的,列表呈指数级增长...到数组的长度不是 2500+2500+2500+2501,而是 2500*2501*4...这对我来说毫无意义.
原来问题出在parSapply
的使用上;我不得不将问题转换为使用 parLapply
,我终于得到了一些可以接受的结果。当按照以下方式重新编码问题时,一切都解决了。注意:我不得不远离 split
因为没有明显的方法可以防止它 运行 它拆分的索引上的模数。相反,我创建了一个按顺序拆分向量的函数。
vsplit<-function(x,f) {
setNames(lapply(f,function (y) x[ceiling((1:length(x))/(length(x)/max(f)))==y]),f)
}
PNorm<-function(x) {
rnorm(length(lt[[x]]),lt[[x]],1)
}
settings<-list(); cores<-settings$cores<-4; N<-10000001
Mean<-rnorm(N,sd=0.7)
SD<-1
lt<-suppressWarnings(vsplit(Mean,1:cores))
cl <<- parallel::makePSOCKcluster(settings$cores)
parallel::clusterSetRNGStream(cl, iseed = round(runif(settings$cores)*1001))
clusterExport(cl,c("lt"))
system.time(
that<-unlist(parLapply(cl,1:cores,PNorm))
)
length(that)
parallel::stopCluster(cl)