2

I have a matrix temp1 (dimensions Nx16) (generally, NxM)

I would like to sum every k columns in each row to one value.

Here is what I got to so far:

cbind(rowSums(temp1[,c(1:4)]), rowSums(temp1[,c(5:8)]), rowSums(temp1[,c(9:12)]), rowSums(temp1[,c(13:16)]))

There must be a more elegant (and generalized) method to do it.

I have noticed similar question here:
sum specific columns among rows

couldn't make it work with Ananda's solution; Got following error:

sapply(split.default(temp1, 0:(length(temp1)-1) %/% 4), rowSums)

Error in FUN(X[[1L]], ...) :
'x' must be an array of at least two dimensions

Please advise.

Community
  • 1
  • 1
YevgenyM
  • 91
  • 1
  • 6

5 Answers5

5

You can use by:

do.call(cbind, by(t(temp1), (seq(ncol(temp1)) - 1) %/% 4, FUN = colSums))
Sven Hohenstein
  • 80,497
  • 17
  • 145
  • 168
4

If the dimensions are equal for the sub matrices, you could change the dimensions to an array and then do the rowSums

 m1 <- as.matrix(temp1)
 n <- 4
 dim(m1) <- c(nrow(m1), ncol(m1)/n, n)
 res <- matrix(rowSums(apply(m1, 2, I)), ncol=n)
 identical(res[,1],rowSums(temp1[,1:4]))
 #[1] TRUE

Or if the dimensions are unequal

  t(sapply(seq(1,ncol(temp2), by=4), function(i) {
                  indx <- i:(i+3)
               rowSums(temp2[indx[indx <= ncol(temp2)]])}))

data

set.seed(24)
temp1 <- as.data.frame(matrix(sample(1:20, 16*4, replace=TRUE), ncol=16))

set.seed(35)
temp2 <- as.data.frame(matrix(sample(1:20, 17*4, replace=TRUE), ncol=17))
akrun
  • 874,273
  • 37
  • 540
  • 662
  • Could you explain this code at all?: m1 <- as.matrix(temp1) n <- 4 dim(m1) <- c(nrow(m1), ncol(m1)/n, n) res <- matrix(rowSums(apply(m1, 2, I)), ncol=n) – wolfsatthedoor Aug 09 '16 at 20:03
  • @robertevansanders First we are converting the 'temp1' to `matrix`, then change it to array (3 D) by changing the dimensions (`dim(m1) <- ...`), then looped by margin 2 with `apply`, do the `rowSums` and convert it to a `matrix` (as it is a vector). – akrun Aug 10 '16 at 03:00
3

Another possibility:

x1<-sapply(1:(ncol(temp1)/4),function(x){rowSums(temp1[,1:4+(x-1)*4])})

## check
x0<-cbind(rowSums(temp1[,c(1:4)]), rowSums(temp1[,c(5:8)]), rowSums(temp1[,c(9:12)]), rowSums(temp1[,c(13:16)]))
identical(x1,x0)
# TRUE
mrip
  • 14,913
  • 4
  • 40
  • 58
1

Here's another approach. Convert the matrix to an array and then use apply with sum.

n <- 4
apply(array(temp1, dim=c(dim(temp1)/c(1,n), n)), MARGIN=c(1,3), FUN=sum)

Using @akrun's data

set.seed(24)
temp1 <- matrix(sample(1:20, 16*4, replace=TRUE), ncol=16)
Matthew Plourde
  • 43,932
  • 7
  • 96
  • 113
1

a function which sums matrix columns with each group of size n columns

set.seed(1618)
mat <- matrix(rnorm(24 * 16), 24, 16)

f <- function(mat, n = 4) {
  if (ncol(mat) %% n != 0)
    stop()
  cols <- split(colSums(mat), rep(1:(ncol(mat) / n), each = n))
  ## or use this to have n mean the number of groups you want
  # cols <- split(colSums(mat), rep(1:n, each = ncol(mat) / n))
  sapply(cols, sum)
}

f(mat, 4)
#          1          2          3          4 
# -17.287137  -1.732936  -5.762159  -4.371258 

c(sum(mat[,1:4]), sum(mat[,5:8]), sum(mat[,9:12]), sum(mat[,13:16]))
# [1] -17.287137  -1.732936  -5.762159  -4.371258

More examples:

## first 8 and last 8 cols
f(mat, 8)
#         1         2 
# -19.02007 -10.13342 

## each group is 16 cols, ie, the entire matrix
f(mat, 16)
#         1 
# -29.15349 

sum(mat)
# [1] -29.15349
rawr
  • 20,481
  • 4
  • 44
  • 78