Search code examples
rmatrixdiagonal

Sum of matrix elements between diagonals efficiently in R


I have data in the form of n*n matrix for which I want to do some computations (e.g. sum) on whose elements placed between diagonals (excluding diagonals).

For example for this matrix:

     [,1] [,2] [,3] [,4] [,5]
[1,]    2    0    1    4    3
[2,]    5    3    6    0    4
[3,]    3    5    2    3    1
[4,]    2    1    5    3    2
[5,]    1    4    3    4    1

The result for sum (between diagonal elements) would be:

# left slice 5+3+2+5 = 15
# bottom slice 4+3+4+5 = 16
# right slice 4+1+2+3 = 10
# top slice 0+1+4+6 = 11

# dput(m)
m <- structure(c(2, 5, 3, 2, 1, 0, 3, 5, 1, 4, 1, 6, 2, 5, 3, 4, 0, 
3, 3, 4, 3, 4, 1, 2, 1), .Dim = c(5L, 5L))

How to accomplish that efficiently?


Solution

  • Here's how you can get the "top slice":

    sum(m[lower.tri(m)[nrow(m):1,] & upper.tri(m)])
    #[1] 11
    

    to visualize it:

    lower.tri(m)[nrow(m):1,] & upper.tri(m)
    #      [,1]  [,2]  [,3]  [,4]  [,5]
    #[1,] FALSE  TRUE  TRUE  TRUE FALSE
    #[2,] FALSE FALSE  TRUE FALSE FALSE
    #[3,] FALSE FALSE FALSE FALSE FALSE
    #[4,] FALSE FALSE FALSE FALSE FALSE
    #[5,] FALSE FALSE FALSE FALSE FALSE
    

    Here's how you can compute all 4 of the slices:

    up <- upper.tri(m)
    lo <- lower.tri(m)
    n <- nrow(m)
    
    # top
    sum(m[lo[n:1,] & up])
    # left
    sum(m[lo[n:1,] & lo])
    # right
    sum(m[up[n:1,] & up])
    # bottom
    sum(m[up[n:1,] & lo])