在空间上将点CSV与多边形Shapefile连接的最快方法


19

我有一个十亿点的CSV文件和一个带有约5,000个多边形的shapefile。在空间上连接点和多边形的最快方法是什么?对于每个点,我需要获取包含的多边形ID。(多边形不重叠。)

通常,我会将两个数据集都加载到PostGIS中。有没有更快的方法来完成工作?

我正在寻找一种开源解决方案。

Answers:


16

如果“最快”包括所花费的时间,则解决方案将取决于您是否熟悉并可以快速使用什么软件。因此,以下备注集中于实现最快的计算时间的构想。

如果您使用固定程序,几乎可以肯定的是,您可以做的最好的事情是对多边形进行预处理,以建立点对点数据结构,例如KD树或四叉树,其性能通常为O(log(V )*(N + V)),其中V是多边形中顶点的总数,N是点数,因为创建数据结构至少需要O(log(V)* V)的努力,然后必须以每点成本O(log(V))为每个点进行探测。

您可以通过首先对多边形进行网格化(利用没有重叠的假设)来做得更好。每个网格单元要么完全位于多边形内部(包括“通用多边形”的内部),在这种情况下,应使用多边形的ID标记该单元,或者它包含一个或多个多边形边。栅格化的成本等于栅格化所有边缘时参考的栅格像元数,其成本为O(V / c),其中c是像元的大小,但是big-O表示法中的隐式常数很小。

(这种方法的一个优点是您可以利用标准的图形例程。例如,如果您有一个系统,该系统(a)使用(b)每个多边形的不同颜色在虚拟屏幕上绘制多边形,并且(c)允许您可以读取要处理的任何像素的颜色,就可以了。)

使用此网格后,通过计算包含每个点的单元格来预筛选点(O(1)操作仅需要几个时钟)。除非这些点聚集在多边形边界周围,否则通常只留下大约O(c)个点,结果不明确。因此,构建网格和进行预筛选的总成本为O(V / c + 1 / c ^ 2)+ O(N)。您必须使用其他方法(例如到目前为止推荐的任何一种方法)来处理其余点(即接近多边形边界的点),而代价为O(log(V)* N * c) 。

随着c变小,具有边缘的同一网格中的点将越来越少,因此需要后续O(log(V))处理的点越来越少。为此,需要存储O(1 / c ^ 2)网格单元并花费O(V / c + 1 / c ^ 2)的时间来对多边形进行栅格化。因此,将有一个最佳的网格大小c。使用它,总的计算成本是O(LOG(V)* N),但隐含常数通常方式比使用罐装程序,由于预筛分的O(N)的速度小。

20年前,我测试了这种方法(在整个英格兰和近海使用均匀间隔的点,并利用当时视频缓冲区提供的大约40万个单元的相对粗略的网格),并且与我可以发表的最佳算法相比,获得了两个数量级的加速找。即使多边形既小又简单(例如三角形),您实际上也可以保证数量级的加速。

以我的经验,计算是如此之快,以至于整个操作都受到数据I / O速度的限制,而不是CPU的限制。预期I / O可能会成为瓶颈,因此,通过将点以尽可能压缩的格式存储以最大程度地减少数据读取时间,可以达到最快的结果。还应考虑如何存储结果,以便可以限制磁盘写入。


6
实现解决方案与计算时间所花费的时间点非常好。如果您通过优化实现了节省的成本(尤其是从雇主的角度来看),那么花很长时间才能获得最佳解决方案才是有益的。
Sasa Ivetic,2011年

5

就我而言,我可能会将CSV数据加载到shp文件中,然后使用shapefileshapely编写python脚本,以获取包含的多边形ID并更新字段值。

我不知道geotools和JTS是否比shapefile / shapely更快...没有时间对其进行测试!

编辑顺便说一句,可能不需要将csv转换为shapefile格式,因为可以很容易地将值格式化为使用多边形shapefile中的空间对象进行测试的值。


4
我将直接使用csv阅读器加载数据并填充Rtree空间索引。Rtree和Shapely的组合具有令人印象深刻的性能(比PostGIS更好;我不了解Java,因此无法与JTS进行比较)。
Mike T

2
如果您不需要一次将所有1b点存储在内存中,则是个好主意。每点至少16个字节(X / Y),您正在查看的数据价值为16GB。如果Rtree将在本地存储上建立索引,那么它肯定会提高性能。将1b点导入单个shapefile也不起作用。OGR规范指出shapefile限制为8GB(建议为4GB)。单点形状使用20个字节。
Sasa Ivetic,2011年

4

我最终将多边形转换为栅格并在点位置对其进行采样。由于我的多边形不重叠且不需要高精度(多边形代表土地使用类别,并且无论如何它们的边界都被认为是不确定的),所以这是我能想到的最省时的解决方案。



3

使用Spatialite

下载GUI。您可以同时打开Shapefile和CSV作为虚拟表。这意味着您实际上并没有将它们导入数据库,而是将它们显示为表,并且您可以按照自己喜欢的任何方式快速加入并查询它们。


3

您可以在C / C ++ / Python中使用OGR相当快地完成此操作(Python应该是3种中最慢的)。遍历所有多边形并在点上设置过滤器,遍历过滤后的点,您将知道遍历的每个点都属于当前多边形。这是使用OGR的python示例代码,它将遍历多边形并相应地过滤点。C / C ++代码看起来与此非常相似,并且我想您会比python显着提高速度。您必须添加几行代码来更新CSV:

from osgeo import ogr
from osgeo.gdalconst import *

inPolyDS = ogr.Open("winnipeg.shp", GA_ReadOnly)
inPolyLayer = inPolyDS.GetLayer(0)
inPointDS = ogr.Open("busstops.vrt", GA_ReadOnly)   
inPointLayer = inPointDS.GetLayerByName("busstops")

inPolyFeat = inPolyLayer.GetNextFeature()
while inPolyFeat is not None:
  inPtFeat = inPointLayer.GetNextFeature()
  while inPtFeat is not None:
    ptGeom = inPtFeat.GetGeometryRef()
    # Do work here...

    inPtFeat = inPointLayer.GetNextFeature()

  inPolyFeat = inPolyLayer.GetNextFeature()

VRT文件(busstops.vrt):

<OGRVRTDataSource>
  <OGRVRTLayer name="busstops">
    <SrcDataSource>busstops.csv</SrcDataSource>
    <GeometryType>wkbPoint</GeometryType>
    <LayerSRS>WGS84</LayerSRS>
    <GeometryField encoding="PointFromColumns" x="X" y="Y" reportSrcColumn="FALSE" />
  </OGRVRTLayer>
</OGRVRTDataSource>

CSV档案(busstops.csv):

FID,X,Y,stop_name
1,-97.1394781371062,49.8712241633646,Southbound Osborne at Mulvey

CSVT文件(busstops.csvt,OGR需要它来标识列类型,否则将不执行空间过滤):

Integer,Real,Real,String

2
那不是遍历10亿个点5000次(每个多边形一次)吗?
昏暗

空间索引是绝对必要的。我之前提到过Rtree,我会再提及一次!
Mike T

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.