如何基于dplyr与sf包按组计算多个多边形的交集?
哈哈,这个问题我之前也遇到过!sf包里st_union配合dplyr::group_by()做多对象并集简直丝滑,但st_intersection()偏偏只能两两处理,确实有点烦。不过咱们结合dplyr的分组和purrr的累积操作就能完美解决,下面给你一步步拆解:
问题回顾
你提到的痛点很准确:用dplyr::group_by() + st_union()计算多多边形并集非常顺手,但st_intersection()默认仅支持两个对象的交集计算,要按组批量处理多个多边形的交集就得动点脑筋。
修正后的示例数据
先把你提供的示例数据调整得更清晰(避免冗余操作):
library(sf) library(dplyr) library(purrr) # 生成三个多边形 s1 <- rbind(c(1, 1), c(10, 1), c(10, 10), c(1, 10), c(1, 1)) %>% list() %>% st_polygon() %>% st_sfc() s2 <- s1 + 4 # 等价于你原来的s2 s3 <- s1 - 4 # 等价于你原来的s3 # 构建分组sf数据框 df <- tibble( group = rep(c(1, 2), each = 3), geometry = rep(list(s1, s2, s3), 2) %>% flatten() ) %>% st_sf()
最优解决方案:分组+累积交集
核心思路是利用交集的结合律((A∩B)∩C = A∩(B∩C)),用purrr::accumulate()对每组的多边形做累积交集,最后取最终的交集结果替换原几何列:
df_final <- df %>% group_by(group) %>% mutate( # 对组内的几何对象做累积交集,最后一个元素就是所有多边形的交集 group_intersection = accumulate(geometry, st_intersection) %>% last() ) %>% ungroup() %>% # 替换原几何列 select(-geometry) %>% rename(geometry = group_intersection)
代码解释
group_by(group):按分组字段划分数据,确保每组内的多边形一起处理accumulate(geometry, st_intersection):依次计算多边形的累积交集:先算第1个和第2个的交集,再用这个结果和第3个计算交集,最终得到一个包含每一步结果的列表last():提取列表的最后一个元素,也就是该组所有多边形的共同交集- 最后通过
select和rename替换原几何列,让每组的所有行都对应该组的交集多边形
注意事项
- 如果组内存在无交集的多边形,
st_intersection会返回空几何,你可以用st_is_empty()来检测并做后续处理(比如过滤这类组) - 确保提前加载
purrr包,accumulate()是它的核心函数之一 - 这个方法同样适用于每组有更多多边形的场景,扩展性很强
内容的提问来源于stack exchange,提问作者Tordir
相关产品推荐
相关产品推荐

