在R中删除矩阵的对角元素

10

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

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

但是我得到了0个数字...


你使用的是哪种计算机语言? - lurker
哪种语言?你指的是删除吗?设置为零? - us2012
@us2012 我的意思是从矩阵中删除它们。 - Titi90
4个回答

19

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<-t(matrix(1:16,nrow=4,ncol=4))(整个过程)将#5转置为我们想要的形式,并将其分配给变量a

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


这个答案实际上并不适用于此例。a <- t(matrix(11:26, nrow=4, ncol=4)) - user1705135

9
以下是一些人工数据,仅供参考:
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

2

请注意,对角线将具有相同的 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

当然,如果你需要其他语言的内容,询问一下会有所帮助。

0

仍然使用基本的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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接