如果向量不太大,最好的方法可能是将
dist
的输出包装到
as.matrix
中,并使用选项
arr.ind=TRUE
的
which
方法。在一个
dist
矩阵中检索索引号的标准方法的唯一缺点是增加了内存使用量,在传递给
dist
的非常大的向量的情况下,这可能变得重要。这是因为将
dist
返回的下三角矩阵转换为常规密集矩阵实际上会使存储的数据量翻倍。
另一种方法是将dist对象转换为列表,使dist的下三角矩阵中的每列表示列表的一个成员。然后可以将列表成员的索引编号和元素位置映射到密集N x N矩阵的列和行号,而不生成矩阵。
以下是这种基于列表的方法的一个可能的实现:
distToList <- function(x) {
idx <- sum(seq(length(x) - 1)) - rev(cumsum(seq(length(x) - 1))) + 1
listDist <- unname(split(dist(x), cumsum(seq_along(dist(x)) %in% idx)))
}
findDistPairs <- function(vec, theDist) {
listDist <- distToList(vec)
inList <- lapply(listDist, is.element, theDist)
matchedCols <- which(sapply(inList, sum) > 0)
if (length(matchedCols) > 0) found <- TRUE else found <- FALSE
if (found) {
matchedRows <- sapply(matchedCols, function(x) which(inList[[x]]) + x )
} else {matchedRows <- integer(length = 0)}
matches <- cbind(col=rep(matchedCols, sapply(matchedRows,length)),
row=unlist(matchedRows))
return(matches)
}
vec1 <- c(2, 3, 6, 12, 17)
findDistPairs(vec1, 5)
代码中可能不太清晰的部分涉及将列表中条目的位置映射到N x N矩阵的列/行值。虽然这些转换并不简单,但却很直观。
在代码中的注释中,我指出了一个在StackOverflow上的答案,该答案被用于将向量拆分为列表。循环(sapply、lapply)在性能方面应该不会有问题,因为它们的范围是O(N)级别的。此代码的内存使用情况主要由列表的存储确定。这种内存使用量应该与dist对象的相似,因为两个对象包含相同的数据。
dist对象在函数distToList()中计算并转换为列表。由于dist计算在任何情况下都是必需的,所以在处理大型向量的情况下,此函数可能需要花费一定时间。如果目标是找到具有不同距离值的多个配对,则最好仅针对给定向量计算listDist一次,并将结果列表存储,例如存储在全局环境中。
长话短说,处理这类问题的常规方法简单快捷。
distMatrix <- as.matrix(dist(vec1)) * lower.tri(diag(vec1))
which(distMatrix == 5, arr.ind = TRUE)
我建议默认使用这种方法。在内存限制达到时,比如对于非常大的向量vec1
的情况下,可能需要使用更复杂的解决方案。上面描述的基于列表的方法可以提供一种解决方法。
f
。然而,我特别编写了一个简化函数:在R中从距离矩阵中提取对角线。 - Zheyuan Li