矩阵中非对角线元素的最小值、最大值和平均值

13

我在 R 中有一个矩阵,我想要得到:

Max off - diagonal elements
Min off – diagonal elements
Mean off –diagonal elements

使用对角线时,我使用了max(diag(A))、min(diag(A))和mean(diag(A)),效果很好。

但对于非对角线,我尝试了

dataD <- subset(A, V1!=V2)

Error in subset.matrix(A, V1 != V2) : object 'V1' not found

使用方法:

colMeans(dataD) # get the mean for columns

但是我无法获取dataD,因为它显示对象“V1”未找到。

谢谢!


你能澄清一下你所说的“非对角线”是什么意思吗?你是指矩阵中除了对角线以外的所有元素,还是指紧挨着对角线上方/下方的行/列? - Gavin Simpson
只需循环遍历矩阵中的元素并忽略对角线元素。有什么问题吗? - user554546
3
@JackManey 在 R 中,当存在向量化解决方案时进行循环是极其低效的。 - Gavin Simpson
6个回答

30

在这里,row()col()助手函数非常有用。使用@James的A,我们可以使用这个小技巧获取上半部分的非对角线:

> A[row(A) == (col(A) - 1)]
[1]  5 10 15

通过以下方式获取矩阵下三角的元素:

> A[row(A) == (col(A) + 1)]
[1]  2  7 12

这些可以推广到任何你想要的对角线:

> A[row(A) == (col(A) - 2)]
[1]  9 14

并且不需要任何子集。

那么,只需在这些值上调用您想要的任何函数即可。例如:

> mean(A[row(A) == (col(A) - 1)])
[1] 10

如果根据我的评论,您的意思是除了对角线之外的所有内容,那么请使用:

> diag(A) <- NA
> mean(A, na.rm = TRUE)
[1] 8.5
> max(A, na.rm = TRUE)
[1] 15
> # etc. using sum(A, na.rm = TRUE), min(A, na.rm = TRUE), etc..

为了让这个不会被忽略,Ben Bolker建议(在评论中)可以更加简洁地使用我之前提到的row()col()函数来完成上面的代码块:

mean(A[row(A)!=col(A)])
min(A[row(A)!=col(A)])
max(A[row(A)!=col(A)])
sum(A[row(A)!=col(A)])

这是一种更好的解决方案。


3
或者 mean(A[row(A)!=col(A)]) 等等。 - Ben Bolker
+1 Ben - 我看到你已经涵盖了那个选项,所以我没有将它编辑到我的代码中。这甚至没有在我的脑海中出现,尽管我正在使用 row()col() 来获取其他部分。完全空白。 - Gavin Simpson
我删掉了我的内容,因为你已经涵盖了大部分,并且提供了更多的解释和示例。 - Ben Bolker
我想获取对角线上下的所有内容的总和、最小值、最大值和平均值,例如在 A 中,以上对角线的总和是 5 + 9 +10 +13 +14 + 15 = 66 ,平均值为 11。 - amhemad ahmad
最后一个代码块展示了如何获取其中的一些。使用 sum()min() 获取另外两个。此外,请参考Ben Bolkers在这里的评论,他有不同的方法。 - Gavin Simpson

7

只需要一行简单的代码:

如果您想要在矩阵A中找到上下两个非对角线的最小值第一四分位数中位数平均值第三四分位数最大值

summary(c(A[upper.tri(A)],A[lower.tri(A)]))


mean(A[lower.tri(A) | upper.tri(A)]) 应该更有效率 - baptiste

4

对于一个适当子集的矩阵,diag将给出其非对角线元素。例如:

A <- matrix(1:16,4)
#upper off-diagonal
diag(A[-4,-1])
[1]  5 10 15
#lower off-diagonal
diag(A[-1,-4])
[1]  2  7 12

1
要获得一个向量,其中包含矩阵的每列或每行的非对角线元素的最大值,需要执行几个步骤。当我在寻求帮助时,被引导来到这里。也许其他人会做同样的事情,所以我提供了这个解决方案,是我根据在这里学到的知识找到的。
关键是创建一个仅包含非对角线元素的矩阵。考虑:
> A <- matrix(c(10,2,3, 4,10,6, 7,8,10), ncol=3)
> A
     [,1] [,2] [,3]
[1,]   10    4    7
[2,]    2   10    8
[3,]    3    6   10
> apply(A, 2, max)
[1] 10 10 10

使用建议的索引方式进行子集选择,A[row(A)!=col(A)] 产生一个按列顺序排列的非对角元素向量:
> v <- A[row(A)!=col(A)]
> v
[1] 2 3 4 6 7 8

将其转换为矩阵后,可以使用apply()函数仅将选择的函数应用于非对角线元素的边缘。以max函数为例:

> A.off <- matrix(v, ncol=3)
> A.off
     [,1] [,2] [,3]
[1,]    2    4    7
[2,]    3    6    8
> v <- apply(A.off, 2, max)
> v
[1] 3 6 8

整个操作可以紧凑而又有点神秘地编码在一行中:
> v <- apply(matrix(A[row(A)!=col(A)], ncol=ncol(A)), 2, max)
> v
[1] 3 6 8

0

只需将矩阵A乘以1-diag(nofelements)

例如,如果A是一个4x4的矩阵,则

mean(A *(1-diag(4))或A *(1-diag(nrow(A)))

当您需要多次运行相同的代码行时,这样做会更快。


-1
除了James的回答之外,我想补充一点,你可以使用diag函数通过A[-diag(A)]直接排除矩阵的所有对角元素。例如,考虑以下代码: summary(A[-diag(A)])

我对这个答案的紧凑性感到非常兴奋,但我认为它实际上并不适用于一般情况。请比较 m <- matrix(2:17,nrow=4); m[-diag(m)]; m[row(m)!=col(m)] - Ben Bolker
真他妈的,你说得对,我的错。对于更大的矩阵,我的想法必须以 A[-which(A %in% diag(A))] 的形式使用,这比你的方法要不那么优雅。 - Wolfgang Pößnecker
我认为那也行不通... diag(A) 返回对角线上的,因此如果在对角线和非对角线元素中有重复的条目,这将失败... - Ben Bolker
嗯,不幸的是,你是正确的。这是我方面的完全失败。最后一次尝试:m[-seq(from=1,by=nrow(m)+1, length.out=nrow(m))]那应该可以工作,虽然它非常不优雅。 - Wolfgang Pößnecker

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