【发布时间】:2020-05-11 09:44:46
【问题描述】:
我正在尝试从大距离矩阵创建dist 对象。我使用 stats::as.dist 时内存不足。例如,我在当前机器上有大约 128 Gb 可用,但 as.dist 在处理 73,000 x 73,000 矩阵(大约 42Gb)时内存不足。鉴于最终的dist 对象应该小于矩阵大小的一半(即它是下三角形,存储为向量),在我看来,应该可以以更节省内存的方式进行此计算方式 - 前提是我们注意不要创建大型中间对象,只需将输入的相关元素直接复制到输出即可。
查看getS3method('as.dist', 'default') 的代码,我发现它使用ans <- m[row(m) > col(m)] 进行计算,这需要创建与输入维数相同的row 和col 矩阵。
我认为我可以使用here 中的算法来改进这一点,以生成下三角形的索引。这是我使用这种方法的尝试。
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 或 Rcpp 解决方案。注意看this answer 到一个相关问题(从2 列位置数据生成全距离矩阵)似乎可以使用RcppArmadillo 来做到这一点,但我没有使用它的经验。
【问题讨论】:
-
请按照这里的建议尝试@mharinga 的解决方案:stackoverflow.com/questions/37407065/…
-
感谢@tushaR 的链接 - 该答案中的包可能有助于更快地生成距离矩阵。但我在做的是不同的。它将距离矩阵转换为 dist 对象。
-
这里没有惊喜。你有 42GB 矩阵 + 21GB 向量,已经是 63GB。您可以尝试使用例如将矩阵放在磁盘上来自包 {bigstatsr} 的 FBM(免责声明:我是作者)。
-
感谢@F.Privé 的建议 - 但我的问题不是磁盘空间不足(我当然可以增加交换大小),而是我应该已经有足够的内存可用矩阵加向量。因此,需要寻找更有效的解决方案来限制所需的磁盘交换量。
-
您没有足够的 RAM 用于 2 个对象 + 其他东西。这就是为什么我建议您将矩阵放在磁盘上。