Я пытаюсь создать dist
объекты из матриц большого расстояния. Я исчерпал память, используя stats::as.dist
. Например, на текущей машине у меня доступно около 128 ГБ, но as.dist
не хватает памяти при обработке матрицы 73 000 x 73 000 (около 42 ГБ). Учитывая, что конечный объект dist
должен быть меньше половины размера матрицы (т. Е. Это нижний треугольник, хранящийся в виде вектора), мне кажется, что можно сделать этот расчет более эффективным с точки зрения памяти. путь - при условии, что мы будем осторожны, чтобы не создавать большие промежуточные объекты, а просто скопировать соответствующие элементы ввода непосредственно в вывод.
Глядя на код для getS3method('as.dist', 'default')
, я вижу, что он выполняет вычисления с использованием ans <- m[row(m) > col(m)]
, что требует создания матриц row
и col
с той же размерностью, что и для ввода.
Я подумал, что смогу улучшить это, используя алгоритм из здесь сгенерировать индексы нижнего треугольника. Вот моя попытка использовать этот метод.
as.dist.new = function(dm, diag = FALSE, upper = FALSE) {
n = dim(dm)[1]
stopifnot(is.matrix(dm))
stopifnot(dim(dm)[2] == n)
k = 1:((n^2 - n)/2)
j <- floor(((2 * n + 1) - sqrt((2 * n - 1) ^ 2 - 8 * (k - 1))) / 2)
i <- j + k - (2 * n - j) * (j - 1) / 2
idx = cbind(i,j)
remove(i,j,k)
gc()
d = dm[idx]
class(d) <- "dist"
attr(d, "Size") <- n
attr(d, "call") <- match.call()
attr(d, "Diag") <- diag
attr(d, "Upper") <- upper
d
}
Это работает отлично на меньших матрицах. Вот простой пример:
N = 10
dm = matrix(runif(N*N), N, N)
diag(dm) = 0
x = as.dist(dm)
y = as.dist.new(dm)
Однако, если мы создаем матрицу большего расстояния, она сталкивается с теми же проблемами с памятью, что и as.dist
.
Например, эта версия дает сбой в моей системе:
N = 73000
dm = matrix(runif(N*N), N, N)
gc()
diag(dm) = 0
gc()
as.dist.new(dm)
У кого-нибудь есть предложения, как выполнить эту операцию более эффективно? R или R cpp решения приветствуются. NB, глядя на этот ответ на связанную проблему (генерирование матрицы полного расстояния из данных местоположения из 2 столбцов), кажется, что возможно сделать это, используя RcppArmadillo
, но у меня нет опыта использования этого.