代码之家  ›  专栏  ›  技术社区  ›  Stan

填写R中距离矩阵中缺失的行/列

  •  2
  • Stan  · 技术社区  · 9 年前

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

    矩阵#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
    

    解决这个问题的最佳方法是什么?我应该对这两个矩阵进行排序,然后填写缺失的列/行,这样我就可以只使用abs(m1-m2),还是有一种方法可以使用行/列标题,使它们在减法时自动“匹配”?

    这些矩阵大约为5000x5000,我将有大约1000个矩阵进行两两比较,因此如果这将使每次计算速度显著加快,我宁愿尝试对数据进行预处理。

    欢迎任何提示或建议。我通常是一个非R程序员,所以我通常会提出的迭代解决方案需要很长时间——我希望用“R方式”做事情会更快。

    2 回复  |  直到 9 年前
        1
  •  2
  •   akrun    9 年前

    我们创建一个名称索引('Un1'),它是 union 第一个(“1”)和第二个(“2”)的名称 matrix 。通过基于“Un1”指定维度和尺寸名称,创建了两个新的0矩阵('m1N','m2N')。通过行/列索引,我们将这些矩阵中的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 .循环通过 列表 具有 lapply 要获取列名,请使用 协会 f 在里面 Reduce , sort 获得 unique 元素。

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

    我们可以创建另一个 列表 具有 矩阵 0的。

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

    我们可以使用“lst”的对应矩阵的行/列索引更改“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='_')
    
        2
  •  2
  •   Colonel Beauvel    9 年前

    另一种方法使用 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