Я использую R для анализа и хотел бы выполнить тест перестановки. Для этого я использую цикл for
, который работает довольно медленно, и я хотел бы сделать код максимально быстрым. Я думаю, что векторизация является ключевой для этого. Однако после нескольких дней попыток я все еще не нашел подходящего решения, как перекодировать это. Я был бы очень признателен за вашу помощь!
У меня есть симметричная матрица с попарно экологическими расстояниями между популяциями ("dist.mat"
). Я хочу случайным образом перемешать строки и столбцы этой матрицы расстояний, чтобы сгенерировать перестановочную матрицу расстояний ("dist.mat.mix"
). Затем я хотел бы сохранить верхние треугольные значения в этой переставленной матрице расстояний (размером "nr.pairs"
). Этот процесс следует повторить несколько раз ("nr.runs"
). Результатом должна быть матрица ("result"
), содержащая переставленные верхние треугольные значения нескольких прогонов, с размерами nrow=nr.runs
и ncol=nr.pairs
. Ниже приведен пример кода R, который делает то, что я хочу, используя цикл for:
# 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, используя аккуратное векторизованное решение. Это вообще возможно?