距离矩阵(一维向量)中的索引等同于 R 中的二维矩阵索引

Index in a dist matrix (1D vector) equivalent to 2D matrix indices, in R

假设我有一个看起来像这样的矩阵,我将其转换为 dist class 对象(没有对角线),然后转换为向量供以后使用。

m  = matrix(c(0,1,2,3, 1,0,3,4, 2,3,0,5, 3,4,5,0), nrow=4)
#m:
     [,1] [,2] [,3] [,4]
[1,]    0    1    2    3
[2,]    1    0    3    4
[3,]    2    3    0    5
[4,]    3    4    5    0
md = as.dist(m, diag=F)
# md:
   1  2  3
2  1      
3  2  3   
4  3  4  5

mdv = as.vector(md)
# 1 2 3 3 4 5

我可以像往常一样使用 [] 访问原始矩阵,并且我可以使用 m[ 3+((2-1)*4) ] 轻松访问一维索引(例如第 3 行,第 2 列)。 dist 对象(和向量)是一维的,但仅由原始矩阵的下三角形组成(并且还缺少每个原始矩阵 col/row 中的一个元素,因为对角线已被删除)。

以后如何访问向量 mdv 中的等效元素?所以例如我如何访问对象 mdvm[3,2](值 3)的等价物? (不是按值,因为可以有重复的值,而是按索引)相关问答解决了 dist 对象上 as.matrix 的类似问题,但这对我不起作用(因为我需要处理向量)。

这个功能怎么样:

fun <- function(r, c){
  stopifnot(r != c)
  if(r > c) (r-2)*(r-1)/2 + c
  else (c-2)*(c-1)/2 + r
}

mdv[fun(1, 2)] # 1
mdv[fun(2, 3)] # 3
mdv[fun(3, 4)] # 5
mdv[fun(2, 1)] # 1
mdv[fun(3, 2)] # 3
mdv[fun(1, 1)] # stop

r == c 的案例应在申请 fun 之前处理。为了方便起见,您可以编写另一个函数来处理这种情况。

有了 lower.tri(, diag = FALSE) distances-vector ("mdv") 你可以 distances-matrix ("m") 的 (1) find the respective dimensions 和 ( 2) 通过减去等效的缺失 "upper.tri".

相应地转换 i + (j - 1)*nrow 索引
ff = function(x, i, j) 
{
    #assumes that 'x' is a valid distances vector that results in correct 'n'
    n = (1 + sqrt(1 + 8 * length(x))) / 2 

    #make sure i >= j
    ii = pmax(i, j); jj = pmin(i, j)

    #insert 0s to handle 'i == j'
    x = c(unlist(lapply(split(x, rep(seq_len(n - 1), (n - 1):1)), 
                        function(X) c(0, X)), FALSE, FALSE), 0)

    #subtract the missing `upper.tri` elements
    x[(ii + (jj - 1L) * n) - cumsum(0:(n - 1))[jj]]
}

例如:

n = 3
m = matrix(0, n, n); m[lower.tri(m)] = runif(choose(n, 2)); m = m + t(m); x = c(as.dist(m))
m
#          [,1]      [,2]      [,3]
#[1,] 0.0000000 0.3796833 0.5199015
#[2,] 0.3796833 0.0000000 0.4770344
#[3,] 0.5199015 0.4770344 0.0000000
m[cbind(c(2, 2, 3, 1), c(3, 2, 1, 2))]
#[1] 0.4770344 0.0000000 0.5199015 0.3796833
ff(x, c(2, 2, 3, 1), c(3, 2, 1, 2))
#[1] 0.4770344 0.0000000 0.5199015 0.3796833

n = 23
m = matrix(0, n, n); m[lower.tri(m)] = runif(choose(n, 2)); m = m + t(m); x = c(as.dist(m))
i = sample(seq_len(n), 25, TRUE); j = sample(seq_len(n), 25, TRUE)
all.equal(m[cbind(i, j)], ff(x, i, j))
#[1] TRUE

等...