Матрица параллельного расстояния в R
В настоящее время я использую встроенную функцию dist для вычисления матрицы расстояний в R.
dist(featureVector,method="manhattan")
В настоящее время это является узким местом приложения, и поэтому идея состояла в том, чтобы парализовать эту задачу (концептуально это должно быть возможно)
Поиск в гугле и на этом форуме не удался.
У кого-нибудь есть идея?
6 ответов
Вот структура для одного маршрута, который вы могли бы пройти. Это не быстрее, чем просто использование dist()
функция, вместо того, чтобы занять много раз дольше. Он обрабатывает параллельно, но даже если время вычислений было уменьшено до нуля, время запуска функции и экспорта переменных в кластер, вероятно, будет больше, чем просто использование dist()
library(parallel)
vec.array <- matrix(rnorm(2000 * 100), nrow = 2000, ncol = 100)
TaxiDistFun <- function(one.vec, whole.matrix) {
diff.matrix <- t(t(whole.matrix) - one.vec)
this.row <- apply(diff.matrix, 1, function(x) sum(abs(x)))
return(this.row)
}
cl <- makeCluster(detectCores())
clusterExport(cl, list("vec.array", "TaxiDistFun"))
system.time(dist.array <- parRapply(cl, vec.array,
function(x) TaxiDistFun(x, vec.array)))
stopCluster(cl)
dim(dist.array) <- c(2000, 2000)
Пакет R amap предоставляет надежные и распараллеленные функции для кластеризации и анализа основных компонентов. Среди этих функций метод Dist предлагает то, что вы ищете: вычисляет и возвращает матрицу расстояний параллельно.
Dist(x, method = "euclidean", nbproc = 8)
Приведенный выше код вычисляет евклидово расстояние с 8 потоками.
Вы также можете использовать parDist
функция пакета parallelDist, специально созданного для параллельных вычислений матрицы расстояний. Преимущества заключаются в том, что пакет доступен в Mac OS, Windows и Linux и уже поддерживает 39 различных мер расстояния (см. ParDist).
Сравнение производительности для манхэттенского расстояния (спецификации системы: Mac OS; Intel Core i7 с 4 ядрами при 2,5 ГГц и включенной гиперпоточностью):
library(parallelDist)
library(amap)
library(wordspace)
library(microbenchmark)
set.seed(123)
x <- matrix(rnorm(2000 * 100), nrow = 2000, ncol = 100)
microbenchmark(parDist(x, method = "manhattan"),
Dist(x, method = "manhattan", nbproc = 8),
dist.matrix(x, method = "manhattan"),
times = 10)
Unit: milliseconds
expr min lq mean median uq max neval
parDist(x, method = "manhattan") 210.9478 214.3557 225.5894 221.3705 237.9829 247.0844 10
Dist(x, method = "manhattan", nbproc = 8) 749.9397 755.7351 797.6349 812.6109 824.4075 844.1090 10
dist.matrix(x, method = "manhattan") 256.0831 263.3273 279.0864 275.1882 296.3256 311.3821 10
С большей матрицей:
x <- matrix(rnorm(10000 * 100), nrow = 10000, ncol = 100)
microbenchmark(parDist(x, method = "manhattan"),
+ Dist(x, method = "manhattan", nbproc = 8),
+ dist.matrix(x, method = "manhattan"),
+ times = 10)
Unit: seconds
expr min lq mean median uq max neval
parDist(x, method = "manhattan") 6.298234 6.388501 6.737168 6.894203 6.947981 7.221661 10
Dist(x, method = "manhattan", nbproc = 8) 22.722947 24.113681 24.326157 24.477034 24.658145 25.301353 10
dist.matrix(x, method = "manhattan") 7.156861 7.505229 7.544352 7.567980 7.655624 7.800530 10
Дальнейшие сравнения производительности можно найти в parallelDist
Виньетка.
Я - пользователь Windows, который ищет эффективный способ вычисления матрицы расстояний, чтобы использовать ее в иерархической кластеризации (например, используя функцию hclust из пакета "stats"). Функция Dist не работает параллельно в Windows, поэтому мне пришлось искать что-то другое, и я обнаружил пакет "пространство слов" Stefan Evert, который содержит dist.matrix
функция. Вы можете попробовать этот код:
X <- data.frame(replicate(1000,sample(0:1,5000,rep=TRUE)))
system.time(d <- dist(X, method = "manhattan"))
system.time(d2 <- as.dist( dist.matrix(as.matrix(X), method="manhattan") ))
Как вы можете видеть, вычисление матрицы расстояний для фрейма данных с 1000 двоичными объектами и 5000 экземплярами происходит намного быстрее с dist.matrix
Вот результаты на моем ноутбуке (i7-6500U):
> system.time(d <- dist(X, method = "manhattan"))
user system elapsed
151.79 0.04 152.59
> system.time(d2 <- as.dist( dist.matrix(as.matrix(X), method="manhattan") ))
user system elapsed
19.19 0.22 19.56
Это решило мою проблему. Здесь вы можете проверить оригинальную ветку, где я ее нашел: http://r.789695.n4.nabble.com/Efficient-distance-calculation-on-big-matrix-td4633598.html
Это не решает это параллельно, но этого достаточно во многих случаях.
Я также работаю с матрицами с большим расстоянием и пытаюсь ускорить вычисления. Уилл Бенсон выше, вероятно, будет прав, когда говорит, что "время запуска функции и экспорта переменных в кластер, вероятно, будет дольше, чем просто использование".
Тем не менее, я думаю, что это относится к матрицам расстояний с небольшим или средним размером. Смотрите пример ниже, используя функции Dist
из пакета amap с 10 процессорами, dist
из статистики пакета, и rdist
из полей пакета, который вызывает функцию Fortran. В первом примере создается матрица расстояний 400 x 400. Вторая создает матрицу расстояний 3103 x 3103.
require(sp)
require(fields)
require(amap)
data(meuse.grid)
meuse.gridA <- meuse.grid[1:400, 1:2]
meuse.gridB <- meuse.grid[, 1:2]
# small distance matrix
a <- Sys.time()
invisible(dist(meuse.gridA, diag = TRUE, upper = TRUE))
Sys.time() - a
Time difference of 0.002138376 secs
a <- Sys.time()
invisible(Dist(meuse.gridA, nbproc = 10, diag = TRUE, upper = TRUE))
Sys.time() - a
Time difference of 0.005409241 secs
a <- Sys.time()
invisible(rdist(meuse.gridA))
Sys.time() - a
Time difference of 0.02312016 secs
# large distance matrix
a <- Sys.time()
invisible(dist(meuse.gridB, diag = TRUE, upper = TRUE))
Sys.time() - a
Time difference of 0.09845328 secs
a <- Sys.time()
invisible(Dist(meuse.gridB, nbproc = 10, diag = TRUE, upper = TRUE))
Sys.time() - a
Time difference of 0.05900002 secs
a <- Sys.time()
invisible(rdist(meuse.gridB))
Sys.time() - a
Time difference of 0.8928168 secs
Обратите внимание, как время вычисления уменьшилось с 0,09845328 секунд до 0,05900002 секунд, используя Dist
по сравнению с dist
когда матрица расстояний была большой (3103 х 3103). Поэтому я бы предложил вам использовать функцию Dist
из пакета amap, если у вас есть несколько доступных процессоров.
Я обнаружил, что параллельный Dist на несколько порядков быстрее, чем dist, и в процессе затрачивает гораздо меньше виртуальной памяти на моем Mac под Microsoft R Open 3.4.0. Слово предупреждения, хотя - мне не повезло, компилируя его на R 3.3.3. Это не перечисляет версию R как зависимость, но я подозреваю, что это так.