nymuffin
nymuffin

Reputation: 77

Taking the sum of blocks within a matrix in R

I have the following 9x9 matrix.

m<-matrix(runif(9*9), nrow = 9, ncol=9)
m

     [,1]       [,2]       [,3]       [,4]       [,5]       [,6]       [,7]       [,8]       [,9]
[1,] 0.2449707 0.81326836 0.72297582 0.03551436 0.82410051 0.29909943 0.13396759 0.71995057 0.03458879
[2,] 0.2715794 0.08984877 0.36775262 0.87896437 0.51941450 0.31631194 0.19142086 0.80257639 0.05081064
[3,] 0.3741446 0.05950594 0.87952538 0.45086034 0.20399313 0.42205156 0.10122543 0.04948101 0.58620932
[4,] 0.8472067 0.56675295 0.52710442 0.35257950 0.70820007 0.30591402 0.25243479 0.81976209 0.06595630
[5,] 0.1034456 0.18511441 0.70661040 0.59577040 0.87518085 0.16782022 0.98967611 0.96391309 0.86283653
[6,] 0.3685605 0.08227258 0.24782776 0.12557143 0.97220534 0.70517827 0.01113961 0.19896752 0.45398202
[7,] 0.1305617 0.29664856 0.21321683 0.83940964 0.91064918 0.67109195 0.92055064 0.08246438 0.86575867
[8,] 0.8799545 0.52515529 0.09592935 0.43177214 0.62089808 0.04079269 0.62836857 0.70525627 0.04421984
[9,] 0.4941711 0.28413734 0.02130229 0.77447519 0.02323584 0.52432477 0.02130935 0.42077756 0.02348518

How can I take the sum of each 3x3 block within this matrix, resulting in the following 3x3 matrix?

     [,1]       [,2]       [,3]
[1,] 2.04235671 3.95031014 2.6702306
[2,] 3.63489532 4.8084201  4.61866806
[3,] 2.94107696 4.83664948 3.71219046

Thanks in advance!

Upvotes: 2

Views: 319

Answers (4)

IceCreamToucan
IceCreamToucan

Reputation: 28695

Other answers here are probably better/faster, but you could also just loop over the blocks

set.seed(15)
m <- matrix(runif(9*9), nrow = 9, ncol=9)

blocksz <- 3
out <- matrix(NA, blocksz, blocksz)
for(i in 1:(nrow(m)/blocksz)){
  for(j in 1:(ncol(m)/blocksz)){
    iblock <- (1:blocksz) + blocksz*(i - 1)
    jblock <- (1:blocksz) + blocksz*(j - 1)
    out[i, j] <- sum(m[iblock, jblock])
  }
}

Or with tidyverse

seq_len(nrow(m)/blocksz) %>% 
  expand.grid(., .) %>% 
  pmap_dbl(~sum(m[1:blocksz + blocksz*(.x - 1), 
                  1:blocksz + blocksz*(.y - 1)])) %>% 
  matrix(blocksz, byrow = T)

Upvotes: 1

MKR
MKR

Reputation: 20095

An option can be as:

set.seed(15)
m<-matrix(runif(9*9), nrow = 9, ncol=9)

split_lst <- split(m, rep(1:3, each=9*3))

mod_m <- cbind(matrix(split_lst[[1]], nrow=3, byrow = TRUE),
               matrix(split_lst[[2]], nrow=3, byrow = TRUE),
               matrix(split_lst[[3]], nrow=3, byrow = TRUE))


sapply(split(colSums(mod_m), rep(1:9, each=3)),sum)

# 1        2        3        4        5        6        7        8        9 
# 5.067493 5.293779 5.342015 4.003959 4.901462 5.236655 6.319576 4.953201 5.571824

Upvotes: 0

Brian Davis
Brian Davis

Reputation: 992

You could also create a template:

tmp <- structure(c(1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 
 2, 3, 3, 3, 4, 4, 4, 3, 3, 3, 4, 4, 4, 3, 3, 3, 4, 4, 4, 5, 5, 
5, 6, 6, 6, 5, 5, 5, 6, 6, 6, 5, 5, 5, 6, 6, 6), .Dim = c(6L, 
9L))

then do something like this:

matrix(sapply(1:6,function(x) sum(m[which(tmp == x)])),3,3)

Upvotes: 0

MrFlick
MrFlick

Reputation: 206263

If we borrow the matsplitter function from this question we can do

set.seed(15)
m<-matrix(runif(9*9), nrow = 9, ncol=9)
matrix(apply(matsplitter(m, 3, 3), 3, sum), ncol=3)
#          [,1]     [,2]     [,3]
# [1,] 5.067493 5.293779 5.342015
# [2,] 4.003959 4.901462 5.236655
# [3,] 6.319576 4.953201 5.571824

which matches the real answers well

sum(m[1:3, 1:3])
# [1] 5.067493
sum(m[1:3, 4:6])
# [1] 4.003959
sum(m[4:6, 1:3])
# [1] 5.293779
sum(m[7:9, 7:9])
# [1] 5.571824

Upvotes: 2

Related Questions