使用 R 交集使用两个 shapefile 层创建多边形内的多边形键

Using R intersections to create a polygons-inside-a-polygon key using two shapefile layers

数据

我有两个 shapefile 标记了巴基斯坦 national and provincial 个选区的边界。

objective

我正在尝试使用 R 创建一个密钥,该密钥将根据这些数据中的坐标生成哪些省级选区 "contained within" 或以其他方式与哪些国家级选区相交的列表。例如,NA-01对应PA-01、PA-02、PA-03; NA-02 对应于 PA-04 和 PA-05 等。(关键将最终用于 link 分离包含国家和省级选举结果的数据框;那部分我已经弄清楚了。)

我只有 basic/intermediate R 技能,主要是通过反复试验学到的,没有使用 R 之外的 GIS 数据的经验。

尝试的解决方案

对于这个问题,我能找到的最接近的解决方案来自 this guide 计算 R 中的交叉区域。但是,我无法成功复制所提出的三种方法中的任何一种(提问者使用一般 TRUE/FALSE 报告交点,或更精确的重叠面积计算)。

代码

# import map files

NA_map <- readOGR(dsn = "./National_Constituency_Boundary", layer = "National_Constituency_Boundary")
PA_map <- readOGR(dsn = "./Provincial_Constituency_Boundary", layer = "Provincial_Constituency_Boundary")

# Both are now SpatialPolygonsDataFrame objects of 273 and 577 elements, respectively.
# If relevant, I used spdpylr to tweak some of data attribute names (for use later when joining to electoral dataframes):

NA_map <- NA_map %>% 
rename(constituency_number = NA_Cons,
     district_name = District,
     province = Province)

PA_map <- PA_map %>%
rename(province = PROVINCE,
     district_name = DISTRICT,
     constituency_number = PA)

# calculate intersections, take one

Results <- gIntersects(NA_map, PA_map, byid = TRUE)
# this creates a large matrix of 157,521 elements

rownames(Results) <- NA_map@data$constituency_number
colnames(Results) <- PA_map@data$constituency_number

尝试添加 rowname/colname 标签时,出现错误消息:

Error in dimnames(x) <- dn : 
  length of 'dimnames' [1] not equal to array extent

没有 rowname/colname 标签,我无法读取覆盖矩阵,并且不确定如何过滤它们以生成有助于制作 NA-PA 密钥的仅 TRUE 交叉点列表。

我还尝试复制其他两个建议的解决方案来计算准确的重叠区域:

# calculate intersections, take two

pi <- intersect(NA_map, PA_map)
# this generates a SpatialPolygons object with 273 elements

areas <- data.frame(area=sapply(pi@polygons, FUN = function(x) {slot(x, 'area')}))
# this calculates the area of intersection but has no other variables
row.names(areas) <- sapply(pi@polygons, FUN=function(x) {slot(x, 'ID')})

这会生成错误消息:

Error in `row.names<-.data.frame`(`*tmp*`, value = c("2", "1", "4", "5",  : 
  duplicate 'row.names' are not allowed
In addition: Warning message:
non-unique value when setting 'row.names': ‘1’ 

因此,当我尝试使用

将区域附加到属性信息时
attArrea <- spCbind(pi, areas)

我收到错误消息

Error in spCbind(pi, areas) : row names not identical

正在尝试第三种方法:

# calculate intersections, take three
pi <- st_intersection(NA_map, PA_map)

产生错误信息:

Error in UseMethod("st_intersection") : 
  no applicable method for 'st_intersection' applied to an object of class "c('SpatialPolygonsDataFrame', 'SpatialPolygons', 'Spatial', 'SpatialPolygonsNULL', 'SpatialVector')"

我知道我的 SPDF 地图不能用于这第三种方法,但从描述中不清楚需要哪些步骤来转换它并尝试这种方法。

请求帮助

对于使用这些方法中的任何一种所必需的更正的任何建议,或指向其他计算方法的指示,将不胜感激。谢谢!

您的代码不是独立的,因此我没有尝试复制您报告的错误。

但是,使用 sf 包(旨在取代 rgeosrgdalsp 包,获得您想要的 'key' 非常简单在不远的将来)。看这里:

library(sf)

# Download shapefiles
national.url <- 'https://data.humdata.org/dataset/5d48a142-1f92-4a65-8ee5-5d22eb85f60f/resource/d85318cb-dcc0-4a59-a0c7-cf0b7123a5fd/download/national-constituency-boundary.zip'
provincial.url <- 'https://data.humdata.org/dataset/137532ad-f4a9-471e-8b5f-d1323df42991/resource/c84c93d7-7730-4b97-8382-4a783932d126/download/provincial-constituency-boundary.zip'
download.file(national.url, destfile = file.path(tempdir(), 'national.zip'))
download.file(provincial.url, destfile = file.path(tempdir(), 'provincial.zip'))

# Unzip shapefiles
unzip(file.path(tempdir(), 'national.zip'), exdir = file.path(tempdir(), 'national'))
unzip(file.path(tempdir(), 'provincial.zip'), exdir = file.path(tempdir(), 'provincial'))

# Read map files
NA_map <- st_read(dsn = file.path(tempdir(), 'national'), layer = "National_Constituency_Boundary")
PA_map <- st_read(dsn = file.path(tempdir(), 'provincial'), layer = "Provincial_Constituency_Boundary")

# Get sparse list representation of intersections
intrs.sgpb <- st_intersects(NA_map, PA_map) 
length(intrs.sgpb) # One list element per national constituency
# [1] 273
print(intrs.sgpb[[1]]) # Indices of provnicial constituencies intersecting with first national constituency
# [1] 506 522 554 555 556
print(PA_map$PROVINCE[intrs.sgpb[[1]]])[1] # Name of first province intersecting with first national constituency
# [1] KHYBER PAKHTUNKHWA

这是一些示例数据

library(raster)
p <- shapefile(system.file("external/lux.shp", package="raster"))
p1 <- aggregate(p, by="NAME_1")
p2 <- p[, 'NAME_2']

所以我们有 p1 区域和 p2 较低级别的分区。

现在我们可以做

x <- intersect(p1, p2)
# or  x <- union(p1, p2)
data.frame(x)

应该(并且)与原来的一样

data.frame(p)[, c('NAME_1', 'NAME_2')]

要获得多边形的面积,您可以

 x$area <- area(x) / 1000000  # divide to get km2

可能有很多 "slivers",非常小的多边形,因为边界略有不同。这对你来说可能无关紧要。

但另一种方法可能是通过质心匹配:

y <- p2
e <- extract(p1, coordinates(p2))
y$NAME_1 <- e$NAME_1
data.frame(y)