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!

[[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'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)

Answer1:

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) )

Answer2:

You can choose your bdeep (row-spec) and bwide (co-spec) parameters near the center of youree matrix dimensions in whatever manner you like and use this simple function to construct your matrix. As long as the bwide and bdeep are equal, and nrow==ncol, you should get square sub-matrices.

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

人吐槽 人点赞

Recommend

Comment

用户名: 密码:
验证码: 匿名发表

你可以使用这些语言

查看评论:R: split matrix into arbitrary number of blocks