我试图使用R来按列来置换矩阵。 然而,它需要很长时间(矩阵是68k x 32k整数)。
我想并行执行(因为每列都是独立置换的)。我怎样才能实现它?它应该与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
}
答案 0 :(得分:4)
首先,我会使用矢量化,这样可以提高效率。
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
重新合并。
可悲的是,这种方式我都无法获得更好的表现。所以,当我回答你的问题时,我不确定它是否有任何帮助。
答案 1 :(得分:3)
免责声明:我是 bigstatsr 包的作者。
您可以使用共享内存(存储在磁盘上的矩阵)并执行此操作:
# devtools::install_github("privefl/bigstatsr")
library(bigstatsr)
# matrix on disk
mat <- FBM(68e3, 32e2, backingfile = "test")
# inialize with 1:nrow(mat) for each column
system.time(
big_apply(mat, a.FUN = function(X, ind) {
print(min(ind))
X[, ind] <- rep(rows_along(X), length(ind))
NULL
}, a.combine = 'c')
) # 15 sec
# permute each column, in parallel
system.time(
big_apply(mat, a.FUN = function(X, ind) {
print(min(ind))
X[, ind] <- apply(X[, ind], 2, sample)
NULL
}, a.combine = 'c', ncores = nb_cores())
) # 27 sec
在十分之一的数据上花费27秒,在整个数据集上花费378秒(在只有2个物理核心和8GB RAM的笔记本电脑上)。