如何让st_intersection返回0值而非剔除无相交的缓冲区要素?
解决
st_intersection剔除无相交要素的问题 要保留所有缓冲区并将无道路相交的缓冲区道路长度设为0,你可以通过空间连接+分组汇总+左连接填充0的方式实现,替代直接依赖st_intersection。以下是优化后的完整代码和逻辑说明:
1. 优化缓冲区生成(替代低效循环写入)
原循环逐个生成缓冲区并写入Shapefile的方式IO开销大,直接批量生成即可:
# 批量生成所有1km缓冲区(假设p_rep是点要素集) buffer_only <- st_buffer(p_rep, dist = dist) %>% # 给每个缓冲区添加唯一标识,用于后续匹配 mutate(buffer_id = row_number())
2. 计算缓冲区内道路总长度
通过空间连接匹配道路与缓冲区,分组汇总后左连接回原缓冲区,补全无道路的0值:
# 读取并转换道路坐标系 roads <- read_sf(dsn = "All_Roads_(v17a).shp") roads.prep <- st_transform(roads, crs = st_crs(buffer_only)) # 空间连接:将道路段关联到对应的相交缓冲区 road_buffer_join <- st_join(roads.prep, buffer_only, join = st_intersects) # 按缓冲区分组,计算单缓冲区内道路总长度 road_length_summary <- road_buffer_join %>% group_by(buffer_id) %>% summarise(total_length_m = sum(st_length(geometry), na.rm = TRUE)) %>% st_drop_geometry() # 移除几何列,方便后续左连接 # 左连接回原缓冲区,将无道路的缓冲区长度设为0 buffer_with_road_length <- buffer_only %>% left_join(road_length_summary, by = "buffer_id") %>% mutate(total_length_m = ifelse(is.na(total_length_m), 0, total_length_m))
关键逻辑说明
st_join(..., join = st_intersects):自动匹配所有与缓冲区相交的道路段,不相交的缓冲区不会出现在连接结果中,但后续左连接可以补全。sum(st_length(geometry), na.rm = TRUE):确保单个缓冲区有多条道路时汇总总长度,na.rm避免空值导致的计算报错。left_join+ifelse:将原缓冲区中未匹配到道路的行(total_length_m为NA)替换为0,完整保留所有缓冲区要素。
替代方案(基于st_intersection的实现)
如果坚持使用st_intersection,可以先计算相交结果再汇总,最后左连接补0:
roads.buff <- sf::st_intersection(roads.prep, buffer_only) %>% mutate(length_m = st_length(geometry)) %>% group_by(buffer_id) %>% summarise(total_length_m = sum(length_m, na.rm = TRUE)) %>% st_drop_geometry() buffer_with_road_length <- buffer_only %>% left_join(roads.buff, by = "buffer_id") %>% mutate(total_length_m = replace_na(total_length_m, 0))
内容的提问来源于stack exchange,提问作者Bridget Wheelock
相关产品推荐
相关产品推荐

