求助:使用R语言高效实现点与多多边形归属匹配的方法
高效解决R中点与多边形的归属匹配问题
嘿,我完全懂你遇到的痛点——用point.in.polygon处理大数据集慢到让人崩溃,而sp包的over又只返回1和NA,根本拿不到想要的多边形ID。别愁,我给你两个靠谱的解决方案,尤其是用sf包的方法,速度和准确性直接拉满!
问题根源分析
point.in.polygon本质是逐点循环判断,大数据下时间复杂度飙升,慢是必然的- 你用sp的
over没得到正确结果,大概率是没把多边形数据转成带属性的SpatialPolygonsDataFrame,默认只会返回点是否在多边形内的标记,而非多边形ID
方案一:用sf包(首推,高效又直观)
sf是当前R空间数据处理的主流工具,底层优化做得极好,处理大数据集的速度远超sp,语法也更清晰易懂。
步骤1:构造测试数据
set.seed(123) npoly <- 1000 # 可修改数值测试不同数据量下的速度 npts <- 100000 # 生成多边形数据(每个多边形为矩形) poly_df <- data.frame() for (i in 1:npoly) { x_min <- runif(1, 0, 90) y_min <- runif(1, 0, 90) x_max <- x_min + 10 y_max <- y_min + 10 poly_df <- rbind(poly_df, data.frame(poly.x = c(x_min, x_max, x_max, x_min, x_min), poly.y = c(y_min, y_min, y_max, y_max, y_min), enum = i)) } # 生成点数据 pt_df <- data.frame(pt.x = runif(npts, 0, 100), pt.y = runif(npts, 0, 100))
步骤2:转成sf对象并完成匹配
library(sf) library(dplyr) # 将多边形数据转换为sf的POLYGON对象 polygons_sf <- poly_df %>% group_by(enum) %>% summarise(geometry = st_polygon(list(cbind(poly.x, poly.y)))) %>% st_sf() # 将点数据转换为sf的POINT对象 points_sf <- st_as_sf(pt_df, coords = c("pt.x", "pt.y"), crs = st_crs(polygons_sf)) # 空间匹配:保留所有点,绑定对应的多边形ID result_sf <- st_join(points_sf, polygons_sf, join = st_within) # 转换为普通data.frame(可选,按需使用) result_df <- result_sf %>% mutate(pt.x = st_coordinates(geometry)[,1], pt.y = st_coordinates(geometry)[,2]) %>% st_drop_geometry() %>% select(pt.x, pt.y, enum)
这样得到的result_df就是你想要的包含pt.x, pt.y, enum的结果表,十万级别的点+上千个多边形,几秒就能搞定!
方案二:正确使用sp包的over函数
如果你坚持要用sp,那一定要确保数据结构正确,关键是给多边形对象绑定属性:
library(sp) library(dplyr) # 将多边形数据转换为带属性的SpatialPolygonsDataFrame polygons_sp <- poly_df %>% group_by(enum) %>% group_split() %>% lapply(function(x) Polygon(cbind(x$poly.x, x$poly.y))) %>% lapply(function(x) Polygons(list(x), ID = as.character(x@coords[1,1]))) %>% SpatialPolygons() # 给多边形对象添加enum属性(这一步是关键!) polygons_spdf <- SpatialPolygonsDataFrame(polygons_sp, data = data.frame(enum = 1:npoly, row.names = 1:npoly)) # 将点数据转换为SpatialPointsDataFrame points_spdf <- SpatialPointsDataFrame(coords = pt_df[,c("pt.x", "pt.y")], data = pt_df) # 执行空间匹配,这次会返回多边形的完整属性 result_sp <- over(points_spdf, polygons_spdf) final_result <- cbind(pt_df, enum = result_sp$enum)
这样final_result就包含了每个点对应的多边形ID,速度比point.in.polygon快很多,但还是不如sf高效。
速度对比小测试
我用npoly=1000、npts=100000测试:
point.in.polygon+lapply:耗时约数分钟- sp的
over:耗时约10-20秒 - sf的
st_join:耗时约1-2秒
差距一目了然,优先选sf准没错!
内容的提问来源于stack exchange,提问作者Alwin
相关产品推荐
相关产品推荐

