填充 R 中距离矩阵中缺失的 rows/columns

Filling in missing rows/columns in distance matrices in R

我有两个距离矩阵..但是它们中的任何一个都可能缺少项目,并且它们可能是乱序的——例如:

矩阵 #1(缺少项目 c)

  a b d 
a 0 2 3 
b 2 0 4 
d 3 4 0 

矩阵 #2(缺少项目 b,并且项目乱序)

  d c a
d 0 1 2 
c 1 0 1 
a 2 1 0 

我想找到矩阵之间的差异,同时假设任何缺失的项目都是 0。因此,我的结果矩阵应该是:

  a b c d
a 0 2 1 1
b 2 0 0 4
c 1 0 0 1
d 1 4 1 0

解决此问题的最佳方法是什么?我应该对两个矩阵进行排序然后填充缺失的 columns/rows 这样我就可以只使用 abs(m1-m2),或者有没有办法使用 row/column 标题让它们自动 "match up" 什么时候减去?

这些矩阵大约为 5000x5000,我将有大约 1000 个矩阵可以进行成对比较,所以我宁愿对数据进行预处理,如果这会使每个计算速度显着加快。

欢迎任何提示或建议。我通常是一名 non-R 程序员,所以我通常会提出的迭代解决方案将永远持续下去——我希望 "R way" 做事的速度会明显加快。

我们创建一个名称索引 ('Un1'),它是第一个 ('m1') 和第二个 ('m2') matrix 名称的 union ].两个新的 0 矩阵('m1N'、'm2N')是通过指定维度和基于 'Un1' 的 dim 名称创建的。通过 row/column 索引,我们将这些矩阵中的 0 值更改为 'm1'、'm2' 中的值,相减并得到绝对值。

Un1 <- sort(union(colnames(m1), colnames(m2)))
m1N <- matrix(0, ncol=length(Un1), nrow=length(Un1), dimnames=list(Un1, Un1))
m2N <- m1N
m1N[rownames(m1), colnames(m1)] <- m1
m2N[rownames(m2), colnames(m2)] <- m2
abs(m1N-m2N)
#  a b c d
#a 0 2 1 1
#b 2 0 0 4
#c 1 0 0 1
#d 1 4 1 0

更新

如果我们有几个对象名称为 m 后跟数字的矩阵,我们可以将它们放在一个 list 中。我们使用 ls 获取对象名称,使用 mget 获取 list 中的值。使用 lapply 遍历 list 获取列名,使用 union 作为 f in Reducesort 获取 unique 元素.

lst <- mget(ls(pattern='m\d+')) #change the pattern accordingly
Un1 <- sort(Reduce(union, lapply(lst, colnames)))

我们可以创建另一个 matrix 为 0 的 list

lst1 <- lapply(seq_along(lst), function(i) 
    matrix(0, ncol=length(Un1), nrow=length(Un1), dimnames=list(Un1, Un1)))

我们可以使用'lst'的对应矩阵的row/column索引改变'lst1'的对应元素使用Map.

lst2 <- Map(function(x,y) {x[rownames(y), colnames(y)] <- y; x}, lst1, lst)

如果我们需要成对差异,combn可能是一个选项

lst3 <- combn(seq_along(lst2),2, FUN=function(x) 
                      list(abs(lst2[[x[1]]]-lst2[[x[2]]])))
names(lst3) <- combn(seq_along(lst2), 2, FUN=paste, collapse='_')

另一种使用match的方法(开始类似于@akrun):

func = function(cols, m)
{
    res = `dimnames<-`(m[match(cols,rownames(m)), match(cols,colnames(m))],
                       list(cols, cols))
    ifelse(is.na(res), 0, res)
}


cols = sort(union(colnames(m1), colnames(m2)))
abs(func(cols,m1) - func(cols,m2))
#  a b c d
#a 0 2 1 1
#b 2 0 0 4
#c 1 0 0 1
#d 1 4 1 0