I have many NDVI tifs and a land cover shp with multiple features.
I want to know average NDVI in forest or grass and other land cover.
I have tried terra::extract
, but it extract by the CODE1
feature,not land TYPE
u <-vect("D:/muusVutm/type_49N.shp")
head(u)
f <- rast("D:/ndvi2001.tif")
f %>% terra::extract(u,fun='mean',na.rm=T)
In ArcGIS Pro, there is a tool called Zonal Statistics as Table
, it could choose which feature of shp can be zonal statistics. But I have too many tifs(may be thousands), it couldn't be use this tool one by one.
Thanks for any help!
Here are three ways to accomplish that.
Example data. We have raster r
and polygons v
and want the mean values for variable "NAME_1"; but the values of "NAME_1" are not unique (the same name is associated with multiple polygons).
library(terra)
r <- rast(system.file("ex/elev.tif", package="terra"))
v <- vect(system.file("ex/lux.shp", package="terra"))
v$NAME_1
# [1] "Diekirch" "Diekirch" "Diekirch" "Diekirch" "Diekirch" "Grevenmacher"
# [7] "Grevenmacher" "Grevenmacher" "Luxembourg" "Luxembourg" "Luxembourg" "Luxembourg"
We could first aggregate the polygons and then use extract
va <- aggregate(v, "NAME_1")
x <- extract(r, va, "mean", na.rm=TRUE, ID=FALSE)
cbind(NAME_1=va$NAME_1, x)
# NAME_1 elevation
#1 Diekirch 403.1779
#2 Grevenmacher 283.8853
#3 Luxembourg 316.1935
Or extract and then aggregate
e <- extract(r, v)
aggregate(e[,-1,drop=FALSE], data.frame(NAME_1=v$NAME_1[e[,1]]), mean, na.rm=TRUE)
# NAME_1 elevation
#1 Diekirch 403.1779
#2 Grevenmacher 283.8853
#3 Luxembourg 316.1935
You can also use zonal
z <- rasterize(v, r, "NAME_1")
zonal(r, z, mean, na.rm=TRUE)
# NAME_1 elevation
#1 Diekirch 403.1779
#2 Grevenmacher 283.8853
#3 Luxembourg 316.1935
In all cases, you can summarize the values of multiple rasters that have the same geometry in one step. For example
rr <- c(r, r/2, r/10)
zonal(rr, z, mean, na.rm=TRUE)
# NAME_1 elevation elevation elevation
#1 Diekirch 403.1779 201.5889 40.31779
#2 Grevenmacher 283.8853 141.9426 28.38853
#3 Luxembourg 316.1935 158.0968 31.61935