【问题标题】:Removing diagonal elements from matrix in R从R中的矩阵中删除对角线元素
【发布时间】:2013-09-16 23:38:39
【问题描述】:

如何使用 R 从矩阵 L 中删除对角线元素 (diagL)?我尝试使用以下内容:

subset(L, select=-diag(L)) or
subset(L, select=-c(diag(L)))

但我得到 0 个数字...

【问题讨论】:

  • 你使用什么计算机语言?
  • 哪种语言?你说的删除是什么意思?设置为零?
  • @us2012 我的意思是从矩阵中删除它们

标签: r matrix diagonal


【解决方案1】:

R 编程语言?我更喜欢C,它更容易拼写。

一种方法是用我喜欢的数字创建一个矩阵:

a<-t(matrix(1:16,nrow=4,ncol=4))

看起来像:

     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12
[4,]   13   14   15   16

删除对角线上的值:

diag(a)=NA

导致:

     [,1] [,2] [,3] [,4]
[1,]   NA    2    3    4
[2,]    5   NA    7    8
[3,]    9   10   NA   12
[4,]   13   14   15   NA

要真正删除这些值,而不是让它们消失,我们需要重铸:

a<-t(matrix(t(a)[which(!is.na(a))],nrow=3,ncol=4))

结果:

     [,1] [,2] [,3]
[1,]    2    3    4
[2,]    5    7    8
[3,]    9   10   12
[4,]   13   14   15

这与我们在上面的 C 中得到的相同。

这有点迂回,但它导致了我认为正确的答案。我很想看到比我更了解 R 的人提供的改进解决方案。

对作业的一点解释:

a<-t(matrix(t(a)[which(!is.na(a))],nrow=3,ncol=4))
  1. !is.na(a) 为我们提供了一个 TRUE、FALSE 值列表,其中元素已被清空。
  2. which(!is.na(a)) 为我们提供了每个真实元素的下标列表。
  3. t(a) 转置矩阵,因为我们需要根据 #2 中的下标进行拉取。
  4. t(a)[which(!is.na(a))] 为我们提供了缺少对角线 NA 值的数字列表。
  5. matrix(t(a)[which(!is.na(a))],nrow=3,ncol=4) 将列表从 #4 转换为矩阵,这是我们想要的转置。
  6. a&lt;-t(matrix(1:16,nrow=4,ncol=4))(整件事)将 #5 转换为我们想要的形式并将其分配给 a 变量。

这适用于a&lt;-t(matrix(11:26,nrow=4,ncol=4)) 等情况。

【讨论】:

  • 这个答案实际上不起作用,例如 a
【解决方案2】:

这里有一些人工数据用于说明:

x <- matrix(1:16, 4, 4)
n <- nrow(x)
x
      [,1] [,2] [,3] [,4]
 [1,]    1    5    9   13
 [2,]    2    6   10   14
 [3,]    3    7   11   15
 [4,]    4    8   12   16

对矩阵x进行向量化后,对角元素对应索引1, n+2, 2*n+3, ...,即序列seq(1, n^2, n+1)。您可以通过

删除这些索引
x[-seq(1,n^2,n+1)]
[1]  2  3  4  5  7  8  9 10 12 13 14 15

在“去除对角线”矩阵后,您可以将下三角矩阵向上移动,得到一个矩阵,n-1 行和n 列由

matrix(x[-seq(1,n^2,n+1)], n-1, n)
     [,1] [,2] [,3] [,4]
[1,]    2    5    9   13
[2,]    3    7   10   14
[3,]    4    8   12   15

或者,这可能是您想要的,您可以将下三角矩阵向右移动,通过转置x 获得具有n 行和n-1 列的矩阵,然后再移除对角线索引并转置它之后回来

t(matrix(t(x)[-seq(1,n^2,n+1)], n-1, n))
     [,1] [,2] [,3]
[1,]    5    9   13
[2,]    2   10   14
[3,]    3    7   15
[4,]    4    8   12

【讨论】:

    【解决方案3】:

    请记住,对角线将具有相同的 X 和 Y 索引。一个将 C 语言中的对角线归零的快速程序如下:

    #include <stdio.h>
    static void printMat(char mat[4][4], char *comment)
    {
        printf("%s:\n", comment);
        for(int jj=0; jj<4; jj++) {
            for(int ii=0; ii<4; ii++) {
                printf("%2d ",mat[jj][ii]);
            }
            printf("\n");
        }
    }
    main()
    {
        static char matrix[4][4]= {
            { 1, 2, 3, 4},
            { 5, 6, 7, 8},
            { 9,10,11,12},
            {13,14,15,16}
        };
    
    
        printMat(matrix,"Before");
        for(int ii=0; ii<4; ii++) {
            matrix[ii][ii]=0;
    
        }
        printMat(matrix,"After");
    }
    

    这会导致:

    Before:
     1  2  3  4
     5  6  7  8
     9 10 11 12
    13 14 15 16
    After:
     0  2  3  4
     5  0  7  8
     9 10  0 12
    13 14 15  0
    

    删除而不是仅仅清除对角线更复杂。

    这应该可以解决问题:(请记住,零字节的 memcpy 可以寻址不存在的元素。)

    #include <stdio.h>
    #include <strings.h>
    static void printMat(char *mat, int xDim, int yDim,char *comment)
    {
        printf("%s:\n", comment);
        for(int jj=0; jj<yDim; jj++) {
            for(int ii=0; ii<xDim; ii++) {
                printf("%2d ",(mat[(jj)*xDim+ii]) );
            }
            printf("\n");
        }
    }
    main()
    {
        static char matrix[4][4]= {
            { 1, 2, 3, 4},
            { 5, 6, 7, 8},
            { 9,10,11,12},
            {13,14,15,16}
        };
        static char new[4][3];
    
        printMat((char*)matrix,4,4,"Before");
    
        for(int ii=0; ii<4; ii++) {
            memcpy(&new[ii][0], &matrix[ii][0],ii);
            memcpy(&new[ii][ii],&matrix[ii][ii+1], 4-ii);
        }
    
        printMat((char*)new,3,4,"After");
    }
    

    结果:

    Before:
     1  2  3  4
     5  6  7  8
     9 10 11 12
    13 14 15 16
    After:
     2  3  4
     5  7  8
     9 10 12
    13 14 15
    

    当然,如果您想要其他语言的内容,询问会有所帮助。

    【讨论】:

      【解决方案4】:

      仍然使用基本的 R,可以使用 upper.tri()lower.tri 的组合在一行中找到您要查找的内容。为了更方便,我创建了一个单行函数。代码如下。

      a <- matrix(rnorm(100), nrow = 4, ncol = 4)
      select_all_but_diag <- function(x) matrix(x[lower.tri(x, diag = F) | upper.tri(x, diag = F)], nrow = nrow(x) - 1, ncol = ncol(x))
      select_all_but_diag(a)
      

      这是之前的矩阵a(在我的例子中):

          [,1] [,2] [,3] [,4]
      [1,]  0.3  2.5 -0.5  2.8
      [2,]  0.7  1.1 -1.4 -0.7
      [3,]  0.9  0.8  1.6  0.5
      [4,] -0.8 -0.3 -0.9  1.6
      

      这是select_all_but_diag(a) 输出矩阵:

         [,1] [,2] [,3] [,4]
      [1,]  0.7  2.5 -0.5  2.8
      [2,]  0.9  0.8 -1.4 -0.7
      [3,] -0.8 -0.3 -0.9  0.5
      

      编辑行专业

      相反,如果您希望折叠以行为主,您可以使用此函数的扩展版本,它允许您折叠矩阵以减少列数而不是行数。

      select_all_but_diag <- function(x, collapse_by = "row") {
        if(collapse_by == "row") matrix(x[lower.tri(x, diag = F) | upper.tri(x, diag = F)], nrow = nrow(x) - 1, ncol = ncol(x))
        else if(collapse_by == "col") t(matrix(t(x)[lower.tri(x, diag = F) | upper.tri(x, diag = F)], nrow = nrow(x) - 1, ncol = ncol(x)))
        else stop("collapse_by accepts only 'row' or 'col'.")
      }
      a
      select_all_but_diag(a, collapse_by = "col")
      

      这是后者的输出:

           [,1] [,2] [,3]
      [1,]  2.5 -0.5  2.8
      [2,]  0.7 -1.4 -0.7
      [3,]  0.9  0.8  0.5
      [4,] -0.8 -0.3 -0.9
      

      【讨论】:

        猜你喜欢
        • 2021-04-16
        • 2023-03-11
        • 1970-01-01
        • 2022-01-07
        • 1970-01-01
        • 1970-01-01
        • 2018-10-20
        • 1970-01-01
        • 2016-06-02
        相关资源
        最近更新 更多