下三角矩陣和指數變換
的距離矩陣是打包格式的下三角矩陣,其中,所述下三角被存儲作爲由列一維向量的盒裝存儲。您可以通過
str(distMatrix)
# Class 'dist' atomic [1:10] 1 4 10 15 3 9 14 6 11 5
# ...
請注意,即使我們稱之爲dist(vec1, diag = TRUE, upper = TRUE)
,結果還是一樣,只是將印刷風格的變化來檢查。總之,無論您如何撥打dist
,您總是會獲得一維數組。
假設一個完整的下三角是n-by-n
,那麼它的第(i,j)
個元素將被映射到打包的1D數組中的第(j - 1) * (2 * n - 2 - j)/2 + (i - 1)
個元素。我們可以定義一個指數變換函數:
## `i` and `j` can both be vector input, but they must have the same length
f <- function (i, j, n) {
ifelse((i > j) & (j <= n), (j - 1) * (2 * n - 2 - j)/2 + (i - 1), NA_real_)
}
在另一方面,如果我們知道包裝的數組中元素的位置,說k
,我們可以通過一個稍微複雜的功能找到(i,j)
:
## `k` can be a vector input
finv <- function (k, n) {
## starting position for each column
ptr_all_cols <- f(2:n, 1:(n - 1), n)
## maximum valid `k`
k_max <- n * (n - 1)/2
## `finv` operation on a scalar `k`
scaler_finv <- function (k) {
if (k > k_max) return(c(i = NA_real_, j = NA_real_))
j <- sum(ptr_all_cols <= k) ## get column index j
i <- k - ptr_all_cols[j] + j + 1 ## get row index i
c(i = i, j = j)
}
## "vectorization"
do.call(rbind, lapply(k, scaler_finv))
}
這些轉換函數在內存使用上非常便宜,因爲它們使用索引而不是矩陣。
基於變換函數finv
隨着finv
有效的解決方案,它是晚飯有效地找到所需的元素。對於你的玩具例如,你可以使用
## the first `5` is the value to be matched; the second is matrix dimension
finv(which(distMatrix == 5), 5)
# i j
#[1,] 5 4
注意
一般來說,距離矩陣包含浮點數。使用==
來判斷兩個浮點數是否相等是相當危險的。閱讀Why are these numbers not equal?瞭解更多和可能的策略。
替代
有由@RHertel提出一個方便的答案。那些擁有10,000聲譽仍然能夠看到它:
mat <- stats:::as.matrix.dist(dist(vec1)) * lower.tri(diag(vec1))
which(mat == 5, arr.ind = TRUE)
另一種方式把第一行是
mat <- matrix(0, n, n); mat[lower.tri(mat)] <- distMatrix
無論哪種方式,將花費更多的內存矩陣過程中存儲了許多n-by-n
矩陣操作(雖然後者相對便宜)。當vec1
很長時,內存問題可能是一個瓶頸。
其它
f
和finv
可能是廣義上非常有用的功能,至少它可以幫助理解全格式和壓縮格式之間的指標怎麼可以相互轉化。
以下兩個函數僅用於演示目的,它還檢查f
和finv
的正確性。
## a function to verbose `f` transform, primarily used to check the correctness of `f`
verbose_f <- function (n) {
i <- rep(seq_len(n), times = n)
j <- rep(seq_len(n), each = n)
matrix(f(i, j, n), n)
}
## a function to verbose `finv` transform, primarily used to check the correctness of `finv`
verbose_finv <- function (k, n) cbind(k = k, finv(k, n))
我們以n = 5
爲例。
verbose_f(5)
# [,1] [,2] [,3] [,4] [,5]
#[1,] NA NA NA NA NA
#[2,] 1 NA NA NA NA
#[3,] 2 5 NA NA NA
#[4,] 3 6 8 NA NA
#[5,] 4 7 9 10 NA
verbose_finv(1:15,5)
# k i j
# [1,] 1 2 1
# [2,] 2 3 1
# [3,] 3 4 1
# [4,] 4 5 1
# [5,] 5 3 2
# [6,] 6 4 2
# [7,] 7 5 2
# [8,] 8 4 3
# [9,] 9 5 3
#[10,] 10 5 4
#[11,] 11 NA NA
#[12,] 12 NA NA
#[13,] 13 NA NA
#[14,] 14 NA NA
#[15,] 15 NA NA
在這兩種情況下,NA
暗示 「下標越界」。
您可以通過點擊旁邊的複選標記,選擇以下最能解決您的問題的答案(假設他們中的任何一個都可以)標記爲「已接受」。這對未來訪問者來說可能是一個有用的指標。 – Frank