我正在尝试使用 R 按列置换矩阵。 然而,它需要很长时间(矩阵是 68k x 32k 整数)。
我想并行进行(因为每一列都是独立排列的)。我怎样才能实现它?应该是和 embarrassingly parallel for in R 有关系,但是没找到解决方法。
目前,我的功能如下:
permMTX <- function(x) {
nr <- nrow(x)
nc <- ncol(x)
# I'd like to parallelize this for, since each
# column can be permuted independently
for (i in 1:nc) {
x[,i] <- x[sample(nr),i]
}
x
}
最佳答案
解决方案
首先,我会利用矢量化,这应该会提高效率。
permMTX = function(x) apply(x, 2L, sample)
然后我们可以使用库 parallel
来并行化该函数:
library(parallel)
parPermMTX = function(x, cluster) parApply(cl = cluster, X = x, MARGIN = 2L, FUN = sample)
用法
使用parallel
,您必须在使用前注册一个集群。这是一个例子:
cl = makeCluster(detectCores(logical = FALSE))
parPermMTX(diag(10), cl)
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0 1 0 0 0
#[2,] 0 0 0 0 0
#[3,] 0 0 0 0 0
#[4,] 1 0 0 1 1
#[5,] 0 0 1 0 0
parallel
的工作方式(产生多个 R 进程)你必须确保你有足够的内存来容纳你的数据的多个副本。
我认为也建议将数据导出到流程中,您只需调用即可做到这一点
clusterExport(cl, varlist = "exampleData")
虽然它确实在我这边并行运行,但它一点也不比简单地使用 apply
快,但我无法使用与你相同规模的数据进行测试,所以我不能确定它会起作用。
这是因为 sample
已经进行了高度优化,因此生成进程的开销比简单地调用 sample
更大。参见 Why is the parallel package slower than just using apply?
在我的系统上,对 68E3 个整数进行 32E3 次采样大约需要 40 秒:
microbenchmark(sample(68E3), times = 32E3)
#Unit: milliseconds
# expr min lq mean median uq max neval
# sample(68000) 1.132273 1.192923 1.290838 1.227912 1.286229 7.880191 32000
也许你的内存不足,使用了硬盘缓存,这真的很慢。
第二个解决方案
那么,如果我们尝试将对 sample
的调用按顺序分配给单个进程会怎样?这是我在这里尝试的:
parPermMTX2 = function(x, cluster) do.call(cbind, parLapply(cl = cluster, X = list(x[,seq(floor(ncol(x)/2))], x[,floor(ncol(x)/2)+seq(ceiling(ncol(x)/2))]), fun = permMTX))
我们将x
分成两半,然后分别调用permMTX
,再与cbind
重新组合。
遗憾的是,这两种方式都无法获得更好的性能。因此,虽然我回答了您的问题,但我不确定它是否有任何帮助。
关于r - 与 R 并行置换矩阵列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48832010/