下三角が列によって1次元ベクトルとして格納され、下三角行列インデックス変換
距離マトリックスがパックフォーマットの下三角行列であり、のパックストレージ。あなたは私たちがdist(vec1, diag = TRUE, upper = TRUE)
を呼び出す場合でも、結果は印刷スタイルの変更点を除いて、まだ同じであることを
str(distMatrix)
# Class 'dist' atomic [1:10] 1 4 10 15 3 9 14 6 11 5
# ...
注意を経由して、これを確認することができます。要約すると、dist
とどう呼んでも、常に1D配列が得られます。
はその(i,j)
番目の要素が充填された1次元アレイで(j - 1) * (2 * n - 2 - j)/2 + (i - 1)
番目の要素にマッピングされ、完全下三角はn-by-n
であると仮定する。私たちはパック配列内の要素の位置を知っていれば、我々はもう少し複雑な関数で(i,j)
を見つけることができ、k
を言って、一方
## `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` 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
注意
を使用することができ、距離行列は、浮動小数点数が含まれています。 2つの浮動小数点数が等しいかどうかを判断するのに、==
を使うのはかなり危険です。より多くの可能な戦略については、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)
もう一つの方法は、いずれかの方法では、マトリックス中にn-by-n
行列の数を格納するため、より多くのメモリの費用がかかります
mat <- matrix(0, n, n); mat[lower.tri(mat)] <- distMatrix
です(後者は比較的安価ですが)。 vec1
が長いとメモリの問題がボトルネックになる可能性があります。
その他
機能f
とfinv
は、少なくとも、それは完全なフォーマットとパック形式の間でインデックスが相互変換することができますどのように理解するのに役立ち、広い意味ではかなり役に立つかもしれません。
次の2つの機能は、デモ目的のためのもので、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
は「subscript out of bound」を意味します。
次の回答を選択すると、その横のチェックマークをクリックして「受け入れ済み」としてマークすることができます。これは、この質問の将来の訪問者にとって有用な指標となり得る。 – Frank