R Terra- 将 LULC 提取到市政当局的 shapefile,每个分类的计数

问题描述 投票:0回答:1

我有一个分类土地利用栅格 (habitat_raster.tif) 和一个约 200 个城市的 shapefile (municipality_shapefile.shp)。我想获得每个城市中每种栖息地类型的面积。市镇由代码唯一标识。

栅格有 2 个类与基于水位的 ID 相关联(class_low,class_high)。请参阅下面的属性表示例:

ID 低级 class_high
1 开放水域 开放水域
2 森林 水淹森林
3 草本 水淹草本植物

到目前为止,请参见以下代码:

#load in municipality as sf object
tmp_municipality_sf <- 
  st_read('spatial_analyses/data/municipality_shapefile.shp') %>% 
  # same projection string as habitat raster
  st_transform(crs = '+proj=aea +lat_0=-6 +lon_0=-63 +lat_1=-13 +lat_2=3 +x_0=6377563.4 +y_0=6356256.9 +datum=WGS84 +units=m +no_defs')

# load raster data 
habitat_raster <- 
  # CRS: Albers Equal Area, resolution (100 x 100):
  terra::rast('data_cleaning/spatial/habitat_raster.tif')

# load raster attribute table
habitat_classes <-
read_csv(habitat_classes.csv)

# set habitat classes as levels
levels(habitat_raster) <- habitat_classes

# crop raster to municipality shapefile
habitat_crop <- 
  habitat_raster %>% 
  terra::crop(tmp_municipality_sf)

我试过使用 terra::extract(),但它为我提供了一个 ID 为 class_low 的数据框,并且它与市政代码无关。

municipality_extract <- 
  tmp_municipality_sf %>% 
  group_by(code) %>% 
  terra::vect() %>% 
  terra::extract(habitat_crop,
                 .,
                 mask = TRUE)

我还尝试将这些值放入市政府的空间数据框中:

municipaltiy_extract_df <-
  tmp_municipality_sf %>%
  mutate(habitats = tmp_municipality_sf %>% 
           terra::vect() %>% 
           terra::extract(habitat_crop,
                          .) %>% 
           # pulls a vector of values for each municipality
           pull())

我不确定我是否可以改用 terra::zonal() 并将每个自治市形状用作“区域”。 但我想要的是一个数据框,其中包含市政代码和列中每个栖息地类别 (km^2) 的面积。我认为最好的方法是从每个栖息地类别中获取像素数,然后计算面积?

mun_code ID_1 ID_2 ID_3
100 10000 5000 2000
101 9500 4000 1500
extract gis raster terra
1个回答
0
投票

示例数据

library(terra)
v <- vect(system.file("ex/lux.shp", package="terra"))
r <- rast(system.file("ex/elev.tif", package="terra"))
r <- round((r-50)/100)
levels(r) <- data.frame(id=1:5, name=c("forest", "water", "urban", "crops", "grass"))

按区域计算每个类别的单元格数量

e <- extract(r, v)
e <- tapply(e[,2], e[,1], table)
e <- do.call(rbind, e)
d <- data.frame(NAME_2 = v$NAME_2, e)
d

#             NAME_2 forest water urban crops grass
#1          Clervaux      0     0    28   459    74
#2          Diekirch      2   123   200    66     3
#3           Redange      0   109   170   170    17
#4           Vianden      0    31    39    57     3
#5             Wiltz      0     1   161   303     8
#6        Echternach     14    76   233     1     0
#7            Remich     50   147    24     0     0
#8      Grevenmacher     19   221   137     2     0
#9          Capellen      0    25   305     0     0
#10 Esch-sur-Alzette      0   190   229    15     0
#11       Luxembourg      0   184   223    16     0
#12           Mersch      0   167   239    14     0

总结每个区域的每个类别覆盖的面积

# compute the area of each cell
a <- cellSize(rast(r[[1]]), unit="km")
x <- c(r, a)

# extract and aggregate
f <- extract(x, v)
f <- aggregate(f[,3], f[,1:2], sum)
names(f)[3] <- "area"
f <- cbind(zone=v$NAME_2[f$ID], f[,-1])
head(f)
#          zone   name      area
#1     Diekirch forest  1.110530
#2   Echternach forest  7.784033
#3       Remich forest 27.951955
#4 Grevenmacher forest 10.591752
#5     Diekirch  water 68.311151
#6      Redange  water 60.668712

重塑为宽格式

f <- reshape(f, idvar="zone", timevar="name", direction="wide")
f <- round(f, 1)
f[is.na(f)] <- 0
f <- f[order(f$zone), ]
f
                zone  area.forest area.water area.urban area.crops area.grass
#12         Capellen         0.0       13.9      170.1        0.0        0.0
#16         Clervaux         0.0        0.0       15.5      253.8       40.9
#1          Diekirch         1.1       68.3      111.1       36.6        1.7
#2        Echternach         7.8       42.3      129.6        0.6        0.0
#13 Esch-sur-Alzette         0.0      106.2      128.0        8.4        0.0
#4      Grevenmacher        10.6      123.2       76.3        1.1        0.0
#14       Luxembourg         0.0      102.7      124.4        8.9        0.0
#15           Mersch         0.0       92.9      133.0        7.8        0.0
#6           Redange         0.0       60.7       94.6       94.5        9.4
#3            Remich        28.0       82.2       13.4        0.0        0.0
#7           Vianden         0.0       17.2       21.6       31.6        1.7
#8             Wiltz         0.0        0.6       89.3      168.0        4.4 

你也可以用

zon al

来计算
rv <- rasterize(v, r, 1:nrow(v))
x <- c(rv, r)
levels(x) <- NULL
names(x) <- c("zone", "lulc")
a <- cellSize(r, unit="km")
zones <- unique(x, as.raster=TRUE)

z <- zonal(a, zones, sum)
g <- na.omit(cats(zones)[[1]])
m <- merge(g, z, by="label")[,3:5]
m$zone <- v$NAME_2[m$zone]
m$lulc <- levels(r)[[1]][m$lulc,2]

head(m)
#              zone  lulc       area
#1         Clervaux urban  15.499144
#2         Clervaux crops 253.829542
#3         Clervaux grass  40.900555
#4 Esch-sur-Alzette water 106.247915
#5 Esch-sur-Alzette urban 128.048387
#6 Esch-sur-Alzette crops   8.392079
© www.soinside.com 2019 - 2024. All rights reserved.