我在大型数据集(636,688行x 7列)上执行k-means,因此转向并行化。我的结果需要具有可重复性。我可以使用clusterSetRNGStream
包中的parallel
来执行此操作。以下是使用Boston
库中的MASS
数据集的示例:
library(parallel)
cl <- makeCluster(detectCores())
clusterSetRNGStream(cl, iseed = 1234)
clusterEvalQ(cl, library(MASS))
results <- clusterApply(cl, rep(25, 4), function(nstart) kmeans(Boston, 4, nstart = nstart))
check.results <- sapply(results, function(result) result$size)
stopCluster(cl)
每个check.results
列表示针对k-means算法的给定运行的每个相应群集的观察数。我的check.results
看起来像这样:
[,1] [,2] [,3] [,4]
[1,] 38 268 102 102
[2,] 268 98 98 38
[3,] 98 102 38 268
[4,] 102 38 268 98
如果我将results
变量更改为包含rep(25, 2)
而不是rep(25, 4)
,我会得到:
[,1] [,2]
[1,] 38 268
[2,] 268 98
[3,] 98 102
[4,] 102 38
完美 - 前两个'运行'大小保持不变,无论我运行4次迭代还是只运行2次。如果继续更改迭代次数,您将看到每次运行都保持不变。
我的问题 - 如何选择例如第4次运行,特别是没有运行前3次运行?是否在基础 iseed
clusterSetRNGStream
中保存了特定种子?
答案 0 :(得分:4)
clusterSetRNGStream
函数不支持您想要的再现性。问题在于它只是初始化每个集群工作者以从不同的随机数流中提取随机数,这在使用具有给定数量的工作者的clusterApply时是可重现的。但是要执行特定任务,您必须在正确的工作程序上执行它才能获得正确的流,并在该流中快进,即使您知道每个流消耗的随机数的确切数量,也不支持该流。任务。
相反,我建议您使用较低级别的函数为每个任务分配不同的随机数子流。您可以使用nextRNGSubStream
函数生成任务种子:
library(parallel)
# This is based on the clusterSetRNGStream function from
# the parallel package, copyrighted by The R Core Team
getseeds <- function(ntasks, iseed) {
RNGkind("L'Ecuyer-CMRG")
set.seed(iseed)
seeds <- vector("list", ntasks)
seeds[[1]] <- .Random.seed
for (i in seq_len(ntasks - 1)) {
seeds[[i + 1]] <- nextRNGSubStream(seeds[[i]])
}
seeds
}
由于我们没有使用clusterSetRNGStream
,因此在初始化工作人员时需要将随机数生成器设置为“L'Ecuyer-CMRG”:
cl <- makeCluster(detectCores())
clusterEvalQ(cl, { library(MASS); RNGkind("L'Ecuyer-CMRG") })
关键是从worker函数设置“.Random.seed”的值,以便为每个任务使用正确的随机数子流:
worker <- function(nstart, seed, centers=4) {
assign(".Random.seed", seed, envir=.GlobalEnv)
kmeans(Boston, centers, nstart = nstart)
}
由于我们正在迭代nstart
和seed
值,因此您使用clusterMap
而不是clusterApply
来执行任务:
n <- 4
nstarts <- rep(25, n)
seeds <- getseeds(n, 1234)
results <- clusterMap(cl, worker, nstarts, seeds)
要重现第四个任务的结果,请指定第四个种子:
itasks <- c(4)
results <- clusterMap(cl, worker, nstarts[itasks], seeds[itasks])
使用此方法,即使通过clusterMap
.scheduling="dynamic"
参数进行负载平衡,也可以获得可重现的结果,因为结果不依赖于执行任务的工作程序,因为它们使用{{1 }}
请注意,您可以使用clusterSetRNGStream
clusterMap
参数为MoreArgs
函数的centers
参数指定值:
worker