You can iterate through each polygon, mask the raster to the subset polygon, coerce to a vector and then calculate weighted mean using rgeos::gArea to return the area of the subset polygon.
Create some data and plot (ignore projection assignment error).
library(raster)
library(sp)
library(rgeos)
x <- raster(xmn=-110, xmx=-90, ymn=40, ymx=60, ncols=10, nrows=10)
x[] <- runif(ncell(x)) * 10
x <- rasterToPolygons(x, fun=function(x){x > 9})
proj4string(x) <- "+proj=lcc +lat_1=48 +lat_2=33 +lon_0=-100 +ellps=WGS84"
y <- raster(xmn=-110, xmx=-90, ymn=40, ymx=60, nrow=100, ncol=100)
y[] <- runif(ncell(y))
proj4string(y) <- "+proj=lcc +lat_1=48 +lat_2=33 +lon_0=-100 +ellps=WGS84"
plot(y)
plot(x, add=TRUE, lwd=4)
Create a for loop for processing each polygon. The empty results vector is used to accumulate the weighted.mean values. The if else condition checks that there are values associated with the subset and if not assigns a NA.
results <- vector()
for(j in 1:nrow(x)) {
lsub <- x[j, ]
cr <- raster::crop(y, raster::extent(lsub), snap = "out")
fr <- raster::rasterize(lsub, cr)
r <- na.omit(raster::values(raster::mask(x = cr, mask = fr)))
if (length(r) < 1) {
results <- append(results, NA)
} else {
results <- append(results, stats::weighted.mean(r, rep(gArea(lsub),length(r))))
}
}
results
If you want to weight the mean by the area of intersecting raster cells then you can use a similar for loop. The difference here is that we coerce the subset raster to a SpatialPolygonsDataFrame and then use raster::intersect to merge the raster cell polygons with the polygon. We can then use rgeos::gArea to return areas but in this case it is the areas of the raster cell polygons and not the source polygon providing the subset. We have to handle NA values a bit differently.
results <- vector()
for(j in 1:nrow(x)) {
lsub <- x[j, ]
cr <- raster::crop(y, raster::extent(lsub), snap = "out")
r <- as(cr, "SpatialPolygonsDataFrame")
names(r@data) <- "raster.value"
r <- intersect(lsub, r)
na.idx <- which(is.na(r$raster.value))
if(length(na.idx) > 0) { r <- r[-na.idx,] }
if (nrow(r) < 1) {
results <- append(results, NA)
} else {
results <- append(results, weighted.mean(r@data[,"raster.value"], gArea(r, byid=TRUE)))
}
}
results
For weighting by cell proportions, you can also use the raster extract function directly with weights = TRUE and normalizeWeights=TRUE. This is certainly the simple approach however, in benchmark tests it is ~5 times slower that the above for loop. I imagine that this will eventually change as the raster package is consistently under development and this is one of the workhorse functions.
( results <- extract(y, x, weights = TRUE, normalizeWeights=TRUE, fun=mean) )
The results vector is the same length as your SpatialPolygonsDataFrame object and is also ordered so can be joined directly back to the polygons.
x@data <- data.frame(x@data, means=results)
str(x@data)
spplot(x, "means")
Best Answer
The following R example essentially performs what ArcGIS users call Zonal Statistics. This should be a good building block for your analysis. The main function performing this analysis is extract() from the raster package.
Edit:
Here is a simple calculation of the zonal mean using your own shapefile and single band raster:
Which results in the mean pixel value for each polygon.