# R: split matrix into arbitrary number of blocks

Say I have a matrix of values

``` set.seed(1) A <- matrix(runif(25),ncol=5) ```

I'd like to calculate some statistics for approximately square neighborhoods within this matrix of approximately equal size. Either of these kinds of output would do:

``` N1 <- matrix(c(rep(c("A","A","B","B","B"),2),rep(c("C","C","D","D","D"),3)),ncol=5) N2 <- matrix(c(rep(c("A","A","A","B","B"),3),rep(c("C","C","D","D","D"),2)),ncol=5) N1 [,1] [,2] [,3] [,4] [,5] [1,] "A" "A" "C" "C" "C" [2,] "A" "A" "C" "C" "C" [3,] "B" "B" "D" "D" "D" [4,] "B" "B" "D" "D" "D" [5,] "B" "B" "D" "D" "D" N2 [,1] [,2] [,3] [,4] [,5] [1,] "A" "A" "A" "C" "C" [2,] "A" "A" "A" "C" "C" [3,] "A" "A" "A" "D" "D" [4,] "B" "B" "B" "D" "D" [5,] "B" "B" "B" "D" "D" ```

other approximations are also OK, since I can always rotate the matrix. Then I can use these neighborhood matrices to calculate stats using `tapply()`, like this:

``` tapply(A,N1,mean) A B C D 0.6201744 0.5057402 0.4574495 0.5594227 ```

What I want is a function that can make me a matrix of arbitrary dimensions with an arbitrary number of block-like neighborhoods like `N1` or `N2`. I'm having a hard time trying to figure out how such a function would deal with situations where the desired number of blocks are not even squares. `N1` and `N2` have 4 neighborhoods, but say I wanted 5 for some output something like this:

``` N3 <- matrix(c("A","A","B","B","B","A","A","C","C","C","D","D","C","C","C", "D","D","E","E","E","D","D","E","E","E"),ncol=5) [,1] [,2] [,3] [,4] [,5] [1,] "A" "A" "D" "D" "D" [2,] "A" "A" "D" "D" "D" [3,] "B" "C" "C" "E" "E" [4,] "B" "C" "C" "E" "E" [5,] "B" "C" "C" "E" "E" ```

Does anyone know of an existing function that can do this kind of split, or have any ideas on how to make one? Thank you!

[] My final function, taking into account Vincent's advice:

``` DecideBLocks <- function(A,nhoods){ nc <- ncol(A) nr <- nrow(A) nhood_side <- floor(sqrt((nc*nr)/nhoods)) Neighborhoods <- matrix(paste(ceiling(col(A)/nhood_side), ceiling(row(A)/nhood_side), sep="-"), nc=ncol(A)) nhoods.out <- length(unique(c(Neighborhoods))) if (nhoods.out != nhoods){ cat(nhoods.out,"neighborhoods created.\nThese were on average",nhood_side,"by",nhood_side,"cells\nit's a different number than that stated the function tries to round things to square neighborhoods\n") } return(Neighborhoods) } A <- matrix(rnorm(120),12) B <- DecideBLocks(A,13) ```

You can try to play with the `row` and `col` functions: they reduce the problem to a 1-dimensional one. The following defines blocks of size at most 2*2.

```matrix( paste( ceiling(col(A)/2), ceiling(row(A)/2), sep="-"), nc=ncol(A) ) ```

``` mkblk <- function(bwide, bdeep, nrow, ncol){ bstr1 <- c(rep("A", bdeep), rep("B", nrow-bdeep)) bstr2 <- c(rep("C", bdeep), rep("D", nrow-bdeep)) matrix(c( rep(bstr1, bwide), rep(bstr2, ncol-bwide)), ncol=ncol, nrow=nrow)} mkblk(2,2,5,5) [,1] [,2] [,3] [,4] [,5] [1,] "A" "A" "C" "C" "C" [2,] "A" "A" "C" "C" "C" [3,] "B" "B" "D" "D" "D" [4,] "B" "B" "D" "D" "D" [5,] "B" "B" "D" "D" "D" #Test of your strategy tapply(A, mkblk(2,2,5,5), mean) A B C D 0.6201744 0.5057402 0.4574495 0.5594227 ```