4

I'm trying to get the sum of columns in a matrix in R for a certain row. However, I don't want the whole row to be summed but only a specified number of columns i.e. in this case all column above the diagonal. I have tried sum and rowSums function but they are either giving me strange results or an error message. To illustrate, please see example code for an 8x8 matrix below. For the first row I need the sum of the row except item [1,1], for second row the sum except items [2,1] and [2,2] etc.

m1 <- matrix(c(0.2834803,0.6398198,0.0766999,0.0000000,0.0000000,0.0000000,0.0000000,0.0000000,
               0.0000000,0.1101746,0.6354086,0.2544168,0.0000000,0.0000000,0.0000000,0.0000000,
               0.0000000,0.0000000,0.0548145,0.9451855,0.0000000,0.0000000,0.0000000,0.0000000,
               0.0000000,0.0000000,0.0000000,0.3614786,0.6385214,0.0000000,0.0000000,0.0000000,
               0.0000000,0.0000000,0.0000000,0.0000000,0.5594658,0.4405342,0.0000000,0.0000000,
               0.0000000,0.0000000,0.0000000,0.0000000,0.0000000,0.7490395,0.2509605,0.0000000,
               0.0000000,0.0000000,0.0000000,0.0000000,0.0000000,0.0000000,0.5834363,0.4165637,
          0.0000000,0.0000000,0.0000000,0.0000000,0.0000000,0.0000000,0.0000000,1.0000000),
             8, 8, byrow = TRUE, 
             dimnames = list(c("iAAA", "iAA", "iA", "iBBB", "iBB", "iB", "iCCC", "iD"),
                  c("iAAA_p", "iAA_p", "iA_p", "iBBB_p", "iBB_p", "iB_p", "iCCC_p", "iD_p")))

I have tried the following:

rowSums(m1[1, 2:8]) --> Error in rowSums(m1[1, 2:8]) : 
  'x' must be an array of at least two dimensions

Alternatively:

sum(m1[1,2]:m1[1,8]) --> wrong result of 0.6398198 (which is item [1,2])

As I understand rowSums needs an array rather than a vector (although not sure why). But I don't understand why the second way using sum doesn't work. Ideally, there is some way to only sum all columns in a row that lie above the diagonal.

Thanks a lot!

Triamus
  • 2,415
  • 5
  • 27
  • 37

1 Answers1

5

The problem is you are not passing an array to rowSums:

class(m1[1,2:8])
# [1] "numeric"

This is a numeric vector. Use more than a single row and it will work just fine:

class(m1[1:2,2:8])
# [1] "matrix"

rowSums(m1[1:2,2:8])
#     iAAA       iAA 
#0.7165197 1.0000000 

If you want to sum all the columns that lie above the diagonal then you can use lower.tri to set all elements below the diagonal to 0 (or perhaps NA) and then use rowSums. If you do not want to include the diagonal elements themselves you can set diag = TRUE (thanks to @Fabio for pointing this out):

m1[lower.tri(m1 , diag = TRUE)] <- 0
rowSums(m1)
#     iAAA       iAA        iA      iBBB       iBB        iB      iCCC        iD 
#0.7165197 0.8898254 0.9451855 0.6385214 0.4405342 0.2509605 0.4165637 0.0000000 

#  With 'NA'
m1[lower.tri(m1)] <- NA
rowSums(m1,na.rm=T)
#     iAAA       iAA        iA      iBBB       iBB        iB      iCCC        iD 
#0.7165197 0.8898254 0.9451855 0.6385214 0.4405342 0.2509605 0.4165637 0.0000000 
Simon O'Hanlon
  • 58,647
  • 14
  • 142
  • 184
  • Wow! Didn't know lower.tri! – Fabio Marroni Jun 25 '13 at 10:12
  • @SimonO101: Thanks for the quick reply! The thing is that I only need the sums for specific rows and not the whole triangular. – Triamus Jun 25 '13 at 10:21
  • @Triam then `rowSums(m1[ c(1,2,6) , ] )` for the `rowSums` of the first, second and sixth rows for example. I really recommend you read some basic tutorials on subsetting. See `?\`[\`` – Simon O'Hanlon Jun 25 '13 at 10:24
  • @Fabio Marroni: That's a nice solution! What I haven't mentioned here is that I also need the values from the lower triangular for other matrices so I guess I will have to do this in 2 steps. To give you context this is a rating shift/rating transition/rating migration matrix as used in credit analytics. Sometimes I'm interested in both up- and downgrades which is why I would need both triangulars. Thanks a lot! This helps. – Triamus Jun 25 '13 at 10:25
  • @both: sorry I'm new to stack. Can I somehow vote for the answers i.e. that they resolved my question in a good way? Thanks! – Triamus Jun 25 '13 at 10:28
  • @Triam yes you can, but I think you need 15 rep first. You can accept answers by pressing the green check next to your chosen answer (which gets you +2 rep). You get rep when someone upvotes your questions (+5) or answer (+10). Welcome to SO. – Simon O'Hanlon Jun 25 '13 at 10:34
  • @SimonO101: "I really recommend you read some basic tutorials on subsetting" --> I am trying. Pretty new to R still. Thanks for your hint! – Triamus Jun 25 '13 at 10:35