R: splitting a matrix into an arbitrary number of blocks

Let's say I have a matrix of values

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

      

I would like to calculate some statistics for approximately square neighborhoods within this matrix of approximately equal size. Any of these kinds of inference will 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 compute statistics with tapply()

, for example:

    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 am struggling to figure out how such a function would deal with situations where the desired number of blocks is not even squares. N1

and N2

have 4 neighborhoods, but they say that I wanted 5 for some to 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 such a split, or have any ideas on how to create it? Thank!

[[Edit]] 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 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)

      

+2


source to share


2 answers


You can try playing with the functions row

and col

: they reduce the problem to one-dimensional. Blocks of no more than 2 * 2 are defined below.



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

      

+2


source


You can select the bdeep (row-spec) and bwide (co-spec) parameters near the center of the youree matrix dimensions in any way you want and use this simple function to create your matrix. As long as bwide and bdeep are equal and nrow == ncol, you should get square submatrices.



 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 

      

+1


source