ポイントCSVをポリゴンシェープファイルと空間的に結合する最速の方法


19

10億ポイントのCSVファイルと、約5,000のポリゴンを持つシェープファイルがあります。ポイントとポリゴンを空間的に結合する最速の方法は何ですか?各ポイントについて、包含ポリゴンIDを取得する必要があります。(ポリゴンは重なりません。)

通常、両方のデータセットをPostGISにロードします。より速く仕事を終わらせる方法はありますか?

オープンソースのソリューションを探しています。

回答:


16

「最速」の量が含まれている場合、あなたの費やされた時間を、解決策は、あなたが慣れているものをソフトウェアに依存し、迅速に使用することができます。したがって、以下の発言では、可能な限り高速な計算時間を実現するためのアイデアに焦点を当てます。

定型プログラムを使用する場合、ほぼ確実にできる最善の方法は、ポリゴンを前処理して、KDツリーやクワッドツリーなどのパフォーマンスが通常O(log(V )*(N + V))ここで、Vはポリゴン内の頂点の総数、Nはポイントの数です。データ構造は作成に少なくともO(log(V)* V)の労力を要し、その後になります。ポイントごとのコストO(log(V))で各ポイントについてプローブする必要があります。

最初にポリゴンをグリッド化して、重複しないという仮定を活用することで、大幅に改善できます。各グリッドセルは完全にポリゴン内部(「ユニバーサルポリゴン」の内部を含む)にあります。この場合、セルにポリゴンのIDのラベルを付けるか、1つ以上のポリゴンエッジを含みます。このラスタライズのコストは、すべてのエッジのラスタライズ中に参照されるグリッドセルの数に等しく、O(V / c)です。cはセルのサイズですが、big-O表記の暗黙の定数は小さくなります。

(このアプローチの利点の1つは、標準のグラフィックルーチンを活用できることです。たとえば、(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(ログ(V)* N)であるが、暗黙の定数は、典型的には方法、事前スクリーニングのO(N)の速度に起因缶詰の手順を使用してより小さい。

20年前、私はこのアプローチをテストし(イングランドおよびオフショア全体で等間隔のポイントを使用し、当時のビデオバッファーが提供する約400Kセルの比較的粗いグリッドを利用しました)、最高の公開アルゴリズムと比較して2桁のスピードアップを達成しました見つける。ポリゴンが小さくて単純な場合(三角形など)でも、桁違いのスピードアップが実質的に保証されます。

私の経験では、計算は非常に高速であったため、操作全体がCPUではなくデータI / O速度によって制限されていました。I / Oがボトルネックになる可能性があるため、データの読み取り時間を最小限に抑えるために、できるだけ圧縮された形式でポイントを保存することで、非常に高速な結果を達成できます。また、ディスクへの書き込みを制限できるように、結果の保存方法についてもいくつか考えてください。


6
ソリューションの実現とコンピューティング時間の実現に費やした非常に良いポイント。最適なソリューションに到達するまでに長い時間をかけることは、最適化によって(特に雇用者の観点から)これらの節約を実現する場合にのみ有益です。
ササイヴェティック

5

私の場合は、おそらくCSVデータをshpファイルに読み込んでから、shapefileshapelyを使用してPythonスクリプトを記述し、含まれるポリゴンIDを取得してフィールド値を更新します。

geotoolsとJTSがshapefile / shapelyより速いかどうかはわかりません...テストする時間はありません!

編集ところで、値を簡単にフォーマットしてポリゴンシェープファイルの空間オブジェクトでテストできるため、シェープファイル形式へのcsv変換はおそらく必要ありません。


4
csvリーダーを使用してデータを直接ロードし、Rtree空間インデックスを設定します。RtreeとShapelyの組み合わせのパフォーマンスは印象的です(PostGISよりもはるかに優れています。Javaを知らないのでJTSと比較することはできません)。
マイクT

2
一度にすべての1bポイントをメモリに保存する必要がないのであれば、良いアイデアです。ポイントあたり最低16バイト(X / Y)で、16GB相当のデータを見ています。Rtreeがローカルストレージにインデックスを構築する場合、パフォーマンスが確実に向上します。1bポイントを単一のシェープファイルにインポートすることもできません。OGR仕様の状態シェープファイルは8GBに制限されています(4GBを推奨)。シングルポイントシェイプは20バイトを使用します。
ササイヴェティック

4

ポリゴンをラスターに変換し、ポイント位置でサンプリングしました。私のポリゴンは重なり合わず、高い精度は必要なかったため(ポリゴンは土地利用クラスを表し、その境界はとにかく不確かであると見なされていたため)、これは私が思いつく最も時間効率の良いソリューションでした。



3

Spatialiteを使用します。

GUIをダウンロードします。シェープファイルと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
それは、1 bnポイントを5000回ループしませんか(各ポリゴンに1回)?
暗闇

空間インデックスは絶対的である必須。私が言及したRTREEを前に、私は再びそれを言及します!
マイクT

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.