简体   繁体   中英

How can I extract an area weighted sum from a raster into a polygon in R?

I have a raster (of class "RasterLayer") which holds counts of people, N. I have polygons representing administrative boundaries (of class "SpatialPolygonsDataFrame").

I want to extract the values from the raster layer into the polygons, in a way that is weighted by the proportion of the area of the raster tile which overlays the polygon. Say there are four raster tiles, with values (4, 8, 12, 16) overlapping a single polygon. If 25% of each raster overlaps with the polygon, I would expect their contributions to the polygon total to be (1, 2, 3, 4), and the total weighted sum extracted into that polygon to be 10.

Basically, I want to accomplish the following:

 some_polygons$n_people = extract(count_raster$n_people, 
                                   some_polygons, 
                                   fun=sum, 
                                   weights=T, 
                                   na.rm=T)

However, when I run this command in R, I receive the following:

"Warning message: In .local(x, y, ...) : "fun" was changed to "mean"; other functions cannot be used when "weights=TRUE""

R forcibly changes to fun=mean when weights are being used. I need to use weights to account for the proportion of the raster that falls in the polygon, however a mean will not let me compute the quantity I want. I need to find a way to add up counts N in the raster, weighted by the amount of area in the raster which falls inside the polygon (a weighted sum NOT a weighted average). Does anyone know how I can accomplish this?

I am happy to try using other spatial data classes to get this to work. I have tried representing the raster as SpatialPixels , SpatialPoints , and SpatialGrid and working with the sp::over() function, but couldn't figure out how to compute the weighted sum that I need. Help is much appreciated!

First, please make a reproducible example, it would help us to help you ;-)

* EDIT This is valid for the the version raster v2.5-8 but was not for raster v2.3-12 !

The weights are explained as follows:

If TRUE and normalizeWeights=FALSE, the function returns, for each polygon, a matrix with the cell values and the approximate fraction of each cell that is covered by the polygon(rounded to 1/100). If TRUE and normalizeWeights=TRUE the weights are normalized such that they add up to one. The weights can be used for averaging; see examples. This option can be useful (but slow) if the polygons are small relative to the cells size of the Raster* object

So you could use this to compute you weighted sum:

library(raster)
library(sp)

# Reproducible example
set.seed(13)
N = raster(nrows=4, ncol=4, xmn=0, xmx=4, ymn=0, ymx=4)
N[] = runif(16, 50, 100)

Ps1 = Polygons(list(Polygon(cbind(c(0.5,2.8,3.7,1.2,0.5), c(2,3.4,1.2,1.1,2)))), 
               ID = "a")
SPs = SpatialPolygons(list(Ps1))
poly = SpatialPolygonsDataFrame(SPs, data.frame(onecol = c("one"), 
                                                row.names = c("a")))
# See plot below
plot(N)
plot(poly, add=T, border='red')

# Extract with the arguments to get the appropriate weights 
# Check the version of your raster package for normalizeWeights!
myextr = as.data.frame(extract(N, poly, weights=T, normalizeWeights=F))
#      value weight
# 1 69.48172   0.16
# 2 98.10323   0.08
# 3 50.54667   0.61
# 4 78.71476   0.99
# 5 88.21990   0.17
# 6 93.66912   0.17
# 7 52.05317   0.87
# 8 83.05608   0.85
# 9 93.91854   0.43

# compute your weighted sum
mywsum = sum(myextr$value * myextr$weight)
# [1] 314.9164

在此处输入图片说明

* BEFORE EDIT

With raster v2.3-12 , the argument normalizeWeights was apparently not present, hence I had to manually do the job, with a warning about the resolution of the raster compared to the size of the polygon (ie, a fully enclosed cell was needed, otherwise adaptations would have been needed). Hence the two first comments below this answer.

Ps2 = Polygons(list(Polygon(cbind(c(0.5,2.8,3.7,1.2,0.5), c(2,3.4,1.2,0.2,2)))), 
               ID = "a")
SPs2 = SpatialPolygons(list(Ps2))
poly2 = SpatialPolygonsDataFrame(SPs2, data.frame(onecol = c("one"),
                                                  row.names = c("a")))
plot(poly2, add=T, border='blue', lty=3)

myextr2 = as.data.frame(extract(N, poly2, weights=T))

# compute the weight (cells fully enclosed = 1)
myextr2$weight2 = myextr2$weight/max(myextr2$weight)
#       value      weight weight2
# 1  69.48172 0.027777778    0.16
# 2  98.10323 0.013888889    0.08
# 3  50.54667 0.105902778    0.61
# 4  78.71476 0.171875000    0.99
# 5  88.21990 0.029513889    0.17
# 6  93.66912 0.052083333    0.30
# 7  52.05317 0.173611111    1.00
# 8  83.05608 0.173611111    1.00
# 9  93.91854 0.090277778    0.52
# 10 94.52795 0.003472222    0.02
# 11 78.31402 0.107638889    0.62
# 12 79.67737 0.048611111    0.28
# 13 68.22573 0.001736111    0.01

mywsum2 = sum(myextr2$value * myextr2$weight2)
# [1] 428.2086

This demonstrates that the raster package was already GREAT but is still improving :-D

[warning: trying to use normalizeWeights with raster v2.3-12 , it was not crashing nor throwing an error, but not doing the job, so beware and update your version of raster !]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM