多边形中的点

7
我有一百万个点和一个大的形状文件,大小为8GB,在我的系统上无法将其加载到内存中的R中。该形状文件是单层的,因此给定的x,y最多会命中一个多边形,只要它不恰好位于边界上!每个多边形都标有一个严重程度,例如1、2、3。我在一个带有12GB RAM的64位ubuntu机器上使用R。
最简单的方法是如何能够将数据框标记到多边形的严重程度,以便我获得一个带有额外列(即x,y,severity)的数据框?
6个回答

8

仅仅因为你只有一把锤子,并不意味着每个问题都是钉子。

将您的数据加载到PostGIS中,为多边形构建一个空间索引,然后进行单个SQL空间叠加。将结果导出回R。

顺便说一下,说shapefile的大小是8GB并不是非常有用的信息。Shapefile至少由三个文件组成,.shp是几何图形,.dbf是数据库,.shx连接两者。如果您的.dbf是8GB,那么您可以通过替换它来轻松读取形状本身。即使.shp是8GB,它也可能只包含三个多边形,这种情况下简化它们可能很容易。您有多少个多边形,.shp部分的大小是多少?


很高兴看到你发表了答案,Spacedman。我刚才在一些PostGIS文档中搜索,以找出如何执行此操作,因为我认为那可能是正确的工具。 - JD Long

5
我认为您应该预处理数据并创建一个结构,列出网格矩形区域可能的多边形。这样,您可以减少要检查的多边形数量,并且附加结构将适合内存,因为它只有指向多边形的指针。
下面是一个图示:
您想检查黄点在哪个多边形中。通常情况下,您会检查所有多边形,但使用网格优化(橙色线条,没有绘制整个网格,只有其中一个字段),您只需要检查填充的多边形,因为它们都在网格字段内或部分内。
另一种方法是不在内存中存储所有多边形数据,而只存储多边形的边界框,这将仅需要每个多边形2个而不是3个X/Y对(以及指向实际多边形数据的附加指针),但这并不能像第一个建议那样节省太多空间。

谢谢你的回复,schnaader。但是你能给我一些提示如何在R中实现吗?通常对于小的shape文件,我可以直接使用library(maptools)将它们读入内存并访问所有内容,但我不知道如何处理太大而无法加载的shape文件。再次感谢。 - Sean
我迄今为止还没有使用过R,所以我对如何详细操作它完全没有任何想法 :) 但是我认为你应该尝试自己解析文件或将其转换为你可以解析的东西,最好是一些大型文本文件,其中每个多边形都是文件中的一行。 - schnaader
谢谢schnaader - 我会点赞的,但我还没有足够的声望! :-) - Sean
感谢上传图片,JD。 - schnaader
没错!很好的答案,图表也非常有帮助。 - JD Long

4

我很想了解这个问题并想知道你在这方面是否有所进展。既然你问了这个问题,我想你的电脑硬件和软件应该已经得到了提升,可以用来进行相对简单的操作,尽管处理百万个点可能需要较长时间。你可以尝试使用以下方法:

#   Load relevant libraries
library(sp)
library(maptools)
library(spatstat)

#   Read shapefile. Hopefully you have a .prj file with your .shp file
#   otherwise you need to set the proj4string argument. Don't inlcude 
#   the .shp extension in the filename. I also assume that this will
#   create a SpatialPolygonsDataFrame with the "Severity" attribute
#   attached (from your .dbf file).
myshapefile <- readShapePoly("myshapefile_without_extension",     proj4string=CRS("+proj=latlong +datum=WGS84"))


#   Read your location data in. Here I assume your data has two columns X and Y giving     locations
#   Remeber that your points need to be in the same projection as your shapefile. If they aren't
#   you should look into using spTransform() on your shapefile first.
mylocs.df <- read.table(mypoints.csv, sep=",", h=TRUE)

#   Coerce X and Y coordinates to a spatial object and set projection to be the same as
#   your shapefile (WARNING: only do this if you know your points and shapefile are in
#   the same format).
mylocs.sp <- SpatialPoints(cbind(mylocs.df$X,mylocs.df$Y),     proj4string=CRS(proj4string(myshapefile))

#   Use over() to return a dataframe equal to nrows of your mylocs.df
#   with each row corresponding to a point with the attributes from the
#   poylgon in which it fell.
severity.df <- over(mylocs.sp, myshapefile)

希望这个框架能够满足您的需求。但是,您现在可用的计算机/内存是否可以完成此操作是另一回事!


嗨,西蒙,谢谢你的回复 - 内存问题仍然存在,因为其他一些形状文件和光栅文件达到了约40GB!我有2700万个数据点。恰好我们找到了一个更好的快得多的解决方案,使用Python和GDAL - 我马上会回答自己的问题。 - Sean

3
我建议您尝试使用fastshp包。在我的初步测试中,它明显优于其他方法读取shapefiles文件。此外,它还有一个专门的inside函数,可能非常适合您的需求。

代码应该与以下类似:

shp <- read.shp(YOUR_SHP_FILE, format="polygon")) 
inside(shp, x, y)

其中x和y是坐标。

如果那样不行,我会采用@Spacedman提到的PostGIS解决方案。


1
这个答案很快,但目前功能有限。另外,我还没有看到任何关于shapefiles的绘图方法?这方面正在开发吗?不过它确实非常快。 - Simon O'Hanlon
@SimonO101 这是一个相对较新的工具(我认为),因此无法评论其未来功能。您可以使用ggplot2绘制结果。 - radek

3
我没有一个非常好的答案,但是让我提出一个想法。你能否反转问题,不是问每个点适合哪个多边形,而是问“哪些点在每个多边形内?”也许你可以将你的shapefile分成例如2000个县,然后逐步取出每个县并检查每个点是否在该县内。如果一个点在给定的县内,则标记它,并在下一次搜索时将其排除。
同样的思路,你可以将shapefile分成4个区域。然后将单个区域和所有点配合在内存中。然后只需迭代4次数据即可。
另一个想法是使用GIS工具降低shapefile的分辨率(节点和向量数)。当然,这取决于你的用例对精度的重要性。

谢谢JD - 我会点赞的,但我还没有足够的声望! :-) - Sean

3
为了回答我的问题并感谢大家的帮助,最终采用的解决方案是使用Python中的gdal,这相对容易适应栅格和shape文件。其中一些栅格文件达到了约40GB,而一些shape文件超过了8GB,所以它们无论如何都不适合在我们当时拥有的任何计算机内存中(现在我有一台128GB RAM的机器,但我已经转移到新的领域!)。Python/gdal代码能够在1分钟至40分钟内标记2700万个点,具体取决于shapefile中多边形的大小 - 如果有很多小型多边形,则速度非常快 - 如果shapefile中有一些巨大(250k点)的多边形,则速度非常慢!然而,与之前在Oracle空间数据库上运行相比,它需要花费24小时以上来标记2700万个点,或者栅格化和标记需要大约一个小时。正如Spacedman建议的那样,我确实尝试在我的带有SSD的机器上使用PostGIS,但周转时间比使用Python/gdal要慢得多,因为最终的解决方案不需要将shapefiles加载到PostGIS中。因此,总结起来,最快的方法是使用Python/gdal:
  • 将shape文件和x,y csv复制到SSD
  • 修改Python脚本的配置文件,以说明文件在哪里以及要标记哪个图层
  • 并行运行几个图层 - 因为它受CPU限制而不是I/O限制

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接