我正在使用 R 进行数据分析,希望进行一次置换检验。为此,我使用了一个 for
循环,但是速度非常慢,我想尽可能地加快这段代码。 我认为矢量化是解决问题的关键。 然而,经过几天的尝试之后,我仍然没有找到一个合适的解决方案来重新编码它。 我非常感谢您的帮助!
我有一个对称矩阵,其中包含种群之间的生态距离("dist.mat"
)。 我想随机打乱这个距离矩阵的行和列,以生成一个置换后的距离矩阵("dist.mat.mix"
)。 然后,我想保存这个置换后的距离矩阵中的上三角值(大小为 "nr.pairs"
)。 这个过程应该重复几次("nr.runs"
)。结果应该是一个矩阵("result"
),包含多次重复运行的置换上三角值,其维度为nrow=nr.runs
和ncol=nr.pairs
。以下是一个使用 for 循环完成所需操作的示例 R 代码:
# example number of populations
nr.pops <- 20
# example distance matrix
dist.mat <- as.matrix(dist(matrix(rnorm(20), nr.pops, 5)))
# example number of runs
nr.runs <- 1000
# find number of unique pairwise distances in distance matrix
nr.pairs <- nr.pops*(nr.pops-1) / 2
# start loop
result <- matrix(NA, nr.runs, nr.pairs)
for (i in 1:nr.runs) {
mix <- sample(nr.pops, replace=FALSE)
dist.mat.mix <- dist.mat[mix, mix]
result[i, ] <- dist.mat.mix[upper.tri(dist.mat.mix, diag=FALSE)]
}
# inspect result
result
我已经使用base::replicate
函数做了一些笨拙的向量化尝试,但这并没有加速。实际上它更慢了:
# my for loop approach
my.for.loop <- function() {
result <- matrix(NA, nr.runs, nr.pairs)
for (i in 1:nr.runs){
mix <- sample(nr.pops, replace=FALSE)
dist.mat.mix <- dist.mat[mix ,mix]
result[i, ] <- dist.mat.mix[upper.tri(dist.mat.mix, diag=FALSE)]
}
}
# my replicate approach
my.replicate <- function() {
results <- t(replicate(nr.runs, {
mix <- sample(nr.pops, replace=FALSE)
dist.mat.mix <- dist.mat[mix, mix]
dist.mat.mix[upper.tri(dist.mat.mix, diag=FALSE)]
}))
}
# compare speed
require(microbenchmark)
microbenchmark(my.for.loop(), my.replicate(), times=100L)
# Unit: milliseconds
# expr min lq mean median uq max neval
# my.for.loop() 23.1792 24.4759 27.1274 25.5134 29.0666 61.5616 100
# my.replicate() 25.5293 27.4649 30.3495 30.2533 31.4267 68.6930 100
如果您知道如何使用简洁的向量化解决方案加速我的for循环,我将不胜感激。这种方法是否可行?
nr.runs
? - minemnr.pops
是 20,而nr.runs
是 1000。我已经在问题中更新了这个。 - HaRamy.for.loop()
的运行时间为 0.01 秒。你是在多次调用它吗?如果是,调用了多少次?调用该函数1000次需要大约20秒。对我来说这似乎不算慢。 - minemfor
循环是一个重复数亿次的大型计算的一部分。这个大型计算运行了几周时间。即使只是减少这个for
循环的计算时间几微秒,也可以为我节省几个小时甚至几天的运行时间。我发现这个for
循环是我整个计算中最大的瓶颈,因此我想尽可能地让它快速运行。 - HaRasapply
/lapply
相同。而这两者基本上都是“for”循环。https://dev59.com/QlgQ5IYBdhLWcg3wqF2l - minem