Hi all, I need to aggregate some matrix data (1440x720) to a lower dimension (720x360) for lots of years and variables I can do double for loop, but that will be slow. Anybody know a quicker way? here an example with a smaller matrix size: tst=matrix(1:(8*4),ncol=8,nrow=4) tst_2x2=matrix(NA,ncol=4,nrow=2) nx=2 ny=2 for(ilon in seq(1,8,nx)) { for (ilat in seq(1,4,ny)) { ilon_2x2=1+(ilon-1)/nx ilat_2x2=1+(ilat-1)/ny tst_2x2[ilat_2x2,ilon_2x2] = mean(tst[ilat+0:1,ilon+0:1]) } } tst tst_2x2> tst[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [1,] 1 5 9 13 17 21 25 29 [2,] 2 6 10 14 18 22 26 30 [3,] 3 7 11 15 19 23 27 31 [4,] 4 8 12 16 20 24 28 32> tst_2x2[,1] [,2] [,3] [,4] [1,] 3.5 11.5 19.5 27.5 [2,] 5.5 13.5 21.5 29.5 I though a cast to 3d-array might do the trick and apply over the new dimension, but that does not work, since it casts the data along the row.> matrix(apply(array(tst,dim=c(nx,ny,8)),3,mean),nrow=nrow(tst)/ny)[,1] [,2] [,3] [,4] [1,] 2.5 10.5 18.5 26.5 [2,] 6.5 14.5 22.5 30.5 cheers Peter
This should be faster. It uses apply() across the blocks.> ilon <- seq(1,8,nx) > ilat <- seq(1,4,ny) > cells <- as.matrix(expand.grid(ilat, ilon)) > blocks <- apply(cells, 1, function(x) tst[x[1]:(x[1]+1), x[2]:(x[2]+1)]) > block.means <- colMeans(blocks) > tst_2x2 <- matrix(block.means, 2, 4) > tst_2x2[,1] [,2] [,3] [,4] [1,] 3.5 11.5 19.5 27.5 [2,] 5.5 13.5 21.5 29.5 ------------------------------------- David L Carlson Department of Anthropology Texas A&M University College Station, TX 77840-4352 -----Original Message----- From: R-help [mailto:r-help-bounces at r-poject.org] On Behalf Of Anthoni, Peter (IMK) Sent: Wednesday, July 27, 2016 6:14 AM To: r-help at r-project.org Subject: [R] Aggregate matrix in a 2 by 2 manor Hi all, I need to aggregate some matrix data (1440x720) to a lower dimension (720x360) for lots of years and variables I can do double for loop, but that will be slow. Anybody know a quicker way? here an example with a smaller matrix size: tst=matrix(1:(8*4),ncol=8,nrow=4) tst_2x2=matrix(NA,ncol=4,nrow=2) nx=2 ny=2 for(ilon in seq(1,8,nx)) { for (ilat in seq(1,4,ny)) { ilon_2x2=1+(ilon-1)/nx ilat_2x2=1+(ilat-1)/ny tst_2x2[ilat_2x2,ilon_2x2] = mean(tst[ilat+0:1,ilon+0:1]) } } tst tst_2x2> tst[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [1,] 1 5 9 13 17 21 25 29 [2,] 2 6 10 14 18 22 26 30 [3,] 3 7 11 15 19 23 27 31 [4,] 4 8 12 16 20 24 28 32> tst_2x2[,1] [,2] [,3] [,4] [1,] 3.5 11.5 19.5 27.5 [2,] 5.5 13.5 21.5 29.5 I though a cast to 3d-array might do the trick and apply over the new dimension, but that does not work, since it casts the data along the row.> matrix(apply(array(tst,dim=c(nx,ny,8)),3,mean),nrow=nrow(tst)/ny)[,1] [,2] [,3] [,4] [1,] 2.5 10.5 18.5 26.5 [2,] 6.5 14.5 22.5 30.5 cheers Peter ______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
An alternative (more compact, not necessarily faster, because apply is still a for loop inside): f <- function( m, nx, ny ) { # redefine the dimensions of my a <- array( m , dim = c( ny , nrow( m ) %/% ny , ncol( m ) %/% nx ) ) # apply mean over dim 1 apply( a, c( 2, 3 ), FUN=mean ) } f( tst, nx, ny ) -- Sent from my phone. Please excuse my brevity. On July 27, 2016 9:08:32 AM PDT, David L Carlson <dcarlson at tamu.edu> wrote:>This should be faster. It uses apply() across the blocks. > >> ilon <- seq(1,8,nx) >> ilat <- seq(1,4,ny) >> cells <- as.matrix(expand.grid(ilat, ilon)) >> blocks <- apply(cells, 1, function(x) tst[x[1]:(x[1]+1), >x[2]:(x[2]+1)]) >> block.means <- colMeans(blocks) >> tst_2x2 <- matrix(block.means, 2, 4) >> tst_2x2 > [,1] [,2] [,3] [,4] >[1,] 3.5 11.5 19.5 27.5 >[2,] 5.5 13.5 21.5 29.5 > >------------------------------------- >David L Carlson >Department of Anthropology >Texas A&M University >College Station, TX 77840-4352 > > > >-----Original Message----- >From: R-help [mailto:r-help-bounces at r-poject.org] On Behalf Of Anthoni, >Peter (IMK) >Sent: Wednesday, July 27, 2016 6:14 AM >To: r-help at r-project.org >Subject: [R] Aggregate matrix in a 2 by 2 manor > >Hi all, > >I need to aggregate some matrix data (1440x720) to a lower dimension >(720x360) for lots of years and variables > >I can do double for loop, but that will be slow. Anybody know a quicker >way? > >here an example with a smaller matrix size: > >tst=matrix(1:(8*4),ncol=8,nrow=4) >tst_2x2=matrix(NA,ncol=4,nrow=2) >nx=2 >ny=2 >for(ilon in seq(1,8,nx)) { > for (ilat in seq(1,4,ny)) { > ilon_2x2=1+(ilon-1)/nx > ilat_2x2=1+(ilat-1)/ny > tst_2x2[ilat_2x2,ilon_2x2] = mean(tst[ilat+0:1,ilon+0:1]) > } >} > >tst >tst_2x2 > >> tst > [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] >[1,] 1 5 9 13 17 21 25 29 >[2,] 2 6 10 14 18 22 26 30 >[3,] 3 7 11 15 19 23 27 31 >[4,] 4 8 12 16 20 24 28 32 > >> tst_2x2 > [,1] [,2] [,3] [,4] >[1,] 3.5 11.5 19.5 27.5 >[2,] 5.5 13.5 21.5 29.5 > > >I though a cast to 3d-array might do the trick and apply over the new >dimension, but that does not work, since it casts the data along the >row. >> matrix(apply(array(tst,dim=c(nx,ny,8)),3,mean),nrow=nrow(tst)/ny) > [,1] [,2] [,3] [,4] >[1,] 2.5 10.5 18.5 26.5 >[2,] 6.5 14.5 22.5 30.5 > > >cheers >Peter > >______________________________________________ >R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see >https://stat.ethz.ch/mailman/listinfo/r-help >PLEASE do read the posting guide >http://www.R-project.org/posting-guide.html >and provide commented, minimal, self-contained, reproducible code. > >______________________________________________ >R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see >https://stat.ethz.ch/mailman/listinfo/r-help >PLEASE do read the posting guide >http://www.R-project.org/posting-guide.html >and provide commented, minimal, self-contained, reproducible code.