1

I have a symmetric matrix mat:

   A  B  C
A  1  .  .
B  .  1  .
C  .  .  1

And I want to calculate the two highest elements of it. Now since it's a symmetric matrix I thought of using upper.tri like so:

mat.tri<-upper.tri(mat) # convert to upper tri
mat.ord<-order(mat.tri,na.last=TRUE,decreasing=TRUE)[1:2] # order by largest
a.ind<-which(mat%in%mat.tri[mat.ord]) # get absolute indices
r.ind<-arrayInd(a.ind,dim(mat)) # get relative indices
# get row/colnames using these indices

So the above is such a roundabout way of doing things, and even then the output has 'duplicate' rows in that they are just transposed..

Anyone got a more intuitive way of doing this?

Thanks.

Travis Liew
  • 787
  • 1
  • 11
  • 34

2 Answers2

1

Liberally borrowing from the excellent ideas of @SimonO'Hanlon and @lukeA, you can construct a two-liner function to do what you want. I use:

  • arrayInd() to return the array index
  • order() to order the upper triangular elements
  • and the additional trick of setting the lower triangular matrix to NA, using m[lower.tr(m)] <- NA

Try this:

whichArrayMax <- function(m, n=2){
  m[lower.tri(m)] <- NA
  arrayInd(order(m, decreasing=TRUE)[seq(n)], .dim=dim(m))
}

mat <- matrix( c(1,2,3,2,1,5,3,5,1) , 3 , byrow = TRUE )
mat

     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    1    5
[3,]    3    5    1

whichArrayMax(mat, 2)
     [,1] [,2]
[1,]    2    3
[2,]    1    3
Andrie
  • 176,377
  • 47
  • 447
  • 496
0
arrayInd(which.max(mat), .dim=dim(mat))

which is basically the same as which( mat == max(mat) , arr.ind = TRUE )[1,] from @SimonO'Hanlon, but more efficient.

lukeA
  • 53,097
  • 5
  • 97
  • 100
  • Thanks, but what about the max `x` elements and their indices (not including duplicates)? I already know how to get the max element using `which.max`. – Travis Liew Jan 23 '14 at 09:51
  • In that case I'd try sth like `mat[lower.tri(mat, diag=TRUE)] <- NA; arrayInd(which(mat %in% sort(mat, decreasing=TRUE)[1:2]), .dim=dim(mat))` (for x=2) – lukeA Jan 23 '14 at 10:08