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

R: 使用成对组合更新邻接矩阵/数据帧

  •  0
  • CodeNoob  · 技术社区  · 7 年前

    问题


    假设我有这个数据帧:

    # mock data set
    df.size = 10
    cluster.id<- sample(c(1:5), df.size, replace = TRUE)
    letters <- sample(LETTERS[1:5], df.size, replace = TRUE)
    test.set <- data.frame(cluster.id, letters)
    

    将类似于:

         cluster.id letters
            <int>  <fctr>
     1          5       A
     2          4       B
     3          4       B
     4          3       A
     5          3       E
     6          3       D
     7          3       C
     8          2       A
     9          2       E
    10          1       A
    

    现在,我想将它们按集群分组。id并查看在集群中可以找到什么类型的字母,例如 cluster 3 包含字母 A,E,D,C A,A e、 g.): A,E ; A,D, A,C etc. 然后我想在邻接矩阵/数据帧中更新这些组合的成对距离。

    主意


    # group by cluster.id
    # per group get all (unique) pairwise combinations for the letters (excluding pairwise combinations with itself, e.g. A,A)
    # update adjacency for each pairwise combinations
    

    我试过的


    # empty adjacency df
    possible <- LETTERS
    adj.df <- data.frame(matrix(0, ncol = length(possible), nrow = length(possible)))
    colnames(adj.df) <- rownames(adj.df) <- possible
    
    
    # what I tried
    update.adj <- function( data ) {
      for (comb in combn(data$letters,2)) {
        # stucked
      }
    }
    
    test.set %>% group_by(cluster.id) %>% update.adj(.)
    

    可能有一种简单的方法可以做到这一点,因为我一直看到邻接矩阵,但我无法计算出来。。如果不清楚,请告诉我


    回复评论
    回答@Manuel Bickel: 对于我作为示例给出的数据(“will”下的表类似于): 该矩阵将为-->Z对于完整的数据集,请记住这一点。

      A B C D E
    A 0 0 1 1 2
    B 0 0 0 0 0
    C 1 0 0 1 1
    D 1 0 1 0 1
    E 2 0 1 1 0
    

    我会解释我做了什么:

        cluster.id letters
            <int>  <fctr>
     1          5       A
     2          4       B
     3          4       B
     4          3       A
     5          3       E
     6          3       D
     7          3       C
     8          2       A
     9          2       E
    10          1       A
    

    只有包含更多>1个唯一字母是相关的(因为我们不希望与自身组合,例如簇1只包含字母B,因此它会导致组合 B,B 因此不相关):

     4          3       A
     5          3       E
     6          3       D
     7          3       C
     8          2       A
     9          2       E
    

    现在,我寻找每个集群可以进行哪些成对组合:

    集群3 :

    A,E
    A,D
    A,C
    E,D
    E,C
    D,C
    

    更新邻接矩阵中的这些组合:

        A B C D E
        A 0 0 1 1 1
        B 0 0 0 0 0
        C 1 0 0 1 1
        D 1 0 1 0 1
        E 2 0 1 1 0
    

    然后转到下一个群集

    集群2

    A、 E

    再次更新邻接矩阵:

     A B C D E
    A 0 0 1 1 2 <-- note the 2 now
    B 0 0 0 0 0
    C 1 0 0 1 1
    D 1 0 1 0 1
    E 2 0 1 1 0
    

    作为对庞大数据集的反应

    library(reshape2)
    
    test.set <- read.table(text = "
                                cluster.id   letters
                           1          5       A
                           2          4       B
                           3          4       B
                           4          3       A
                           5          3       E
                           6          3       D
                           7          3       C
                           8          2       A
                           9          2       E
                           10          1       A", header = T, stringsAsFactors = F)
    
    x1 <- reshape2::dcast(test.set, cluster.id ~ letters)
    
    x1
    #cluster.id A B C D E
    #1          1 1 0 0 0 0
    #2          2 1 0 0 0 1
    #3          3 1 0 1 1 1
    #4          4 0 2 0 0 0
    #5          5 1 0 0 0 0
    
    x2 <- table(test.set)
    
    x2
    #          letters
    #cluster.id A B C D E
    #         1 1 0 0 0 0
    #         2 1 0 0 0 1
    #         3 1 0 1 1 1
    #         4 0 2 0 0 0
    #         5 1 0 0 0 0
    
    
    x1.c <- crossprod(x1)
    #Error in crossprod(x, y) : 
    #  requires numeric/complex matrix/vector arguments
    
    x2.c <- crossprod(x2)
    #works fine
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   Manuel Bickel    7 年前

    在上面的评论之后,这里是Tyler Rinker与您的数据一起使用的代码。我希望这就是你想要的。

    更新: 在下面的评论之后,我添加了一个使用该包的解决方案 reshape2 为了能够处理大量数据。

    test.set <- read.table(text = "
                                cluster.id   letters
                           1          5       A
                           2          4       B
                           3          4       B
                           4          3       A
                           5          3       E
                           6          3       D
                           7          3       C
                           8          2       A
                           9          2       E
                           10          1       A", header = T, stringsAsFactors = F)
    
    x <- table(test.set)
    x
              letters
    #cluster.id A B C D E
    #         1 1 0 0 0 0
    #         2 1 0 0 0 1
    #         3 1 0 1 1 1
    #         4 0 2 0 0 0
    #         5 1 0 0 0 0
    
    #base approach, based on answer by Tyler Rinker
    x <- crossprod(x)
    diag(x) <- 0 #this is to set matches such as AA, BB, etc. to zero
    x
    
    #         letters
    # letters 
    #         A B C D E
    #       A 0 0 1 1 2
    #       B 0 0 0 0 0
    #       C 1 0 0 1 1
    #       D 1 0 1 0 1
    #       E 2 0 1 1 0
    
    #reshape2 approach
    x <- acast(test.set, cluster.id ~ letters)
    x <- crossprod(x)
    diag(x) <- 0
    x
    #   A B C D E
    # A 0 0 1 1 2
    # B 0 0 0 0 0
    # C 1 0 0 1 1
    # D 1 0 1 0 1
    # E 2 0 1 1 0