**1) `resample` results in 50% improvement** I was able to get about 50% improvement by resampling directly from the `cld` raster to a new raster with the same extent/resolution as `r` and a nearest neighbor sampling method: system.time({ mat<-as.data.frame(getValues(r)) mat$landuse<- NA mat$landuse<-getValues(resample(cld,r,method='ngb')) }) user system elapsed 188.47 5.82 195.01 **2) Parallelization could get you a lot more** That will improve things significantly but you can get massive improvement if you can parallelize this. R comes with a couple parallelization backends and they all run through `foreach`. I assume you are going to either process `mat` in place or save it for later. Since it takes so much work to get that resampled data let's just assume we'll save it for later. The most convenient form is probably a raster alongside the `data_robin` files. library(foreach) library(doMC) library(tools) # Specify the number of workers (should be less than the number of cores in your machine) registerDoMC(2) # Assume you have an array of filenames called 'files' foreach (i=1:length(filenames), .packages=c('raster')) %dopar% { r <- stack(paste0(path, "/data_robin/", files[i])) outFilename=paste0(path, "/data_robin/", file_path_sans_ext(files[i]), "_cld.tif") cldResampled <- resample(cld,r,method='ngb') writeRaster(cldResampled, filename=outFilename, format="GTiff") } One of the drawbacks of the parallel `foreach` is that it's hard to tell when something goes wrong. It would be good to do this serially first by replacing the `%dopar%` with `%do%` until you know it is working, and then let it run through the whole thing.