RTreeでの空間インデックスの使用を理解していますか?


13

RTreeでの空間インデックスの使用を理解できません。

例:300個のバッファーポイントがあり、各バッファーの交差領域とポリゴンシェープファイルを知る必要があります。ポリゴンシェープファイルには、20,000を超えるポリゴンがあります。プロセスを高速化するために空間インデックスを使用することが提案されました。

SO ...ポリゴンシェープファイルの空間インデックスを作成する場合、何らかの方法でファイルに「アタッチ」されますか、それともインデックスはスタンドアロンですか?つまり、作成後、ポリゴンファイルで交差関数を実行するだけで、より高速な結果を得ることができますか?交差点は空間インデックスがあることを「認識」し、何をすべきかを知っていますか?または、インデックスで実行してから、FIDなどを介して元のポリゴンファイルにそれらの結果を関連付ける必要がありますか?

RTreeのドキュメントはあまり役に立ちません(おそらくプログラミングを学んでいるだけだからです)。手動で作成されたポイントを読み取り、それから他の手動で作成されたポイントに対してクエリを実行して、ウィンドウ内に含まれるIDを返すことにより、インデックスを作成する方法を示します。理にかなっています。しかし、インデックスの元のファイルにどのように関連するかについては説明していません。

私はそれがこのような何かに行かなければならないと考えています:

  1. ポリゴンシェープファイルから各ポリゴンフィーチャのbboxを取得し、空間インデックスに配置して、シェープファイル内のIDと同じIDを与えます。
  2. そのインデックスをクエリして、交差するIDを取得します。
  3. 次に、インデックスのクエリによって特定された元のシェープファイル内のフィーチャのみで交差を再実行します(この最後の部分をどのように行うかはわかりません)。

正しいアイデアはありますか?私は何かが欠けていますか?


現在、このコードを、1つのポイントフィーチャのみを含む1つのポイントシェープファイルと、20,000個以上のポリゴンフィーチャを含む1つのポリゴンシェープファイルで動作するようにしています。

Fionaを使用してシェープファイルをインポートし、RTreeを使用して空間インデックスを追加し、Shapelyを使用して交差を試みています。

私のテストコードは次のようになります。

#point shapefile representing location of desired focal statistic
traps = fiona.open('single_pt_speed_test.shp', 'r') 

#polygon shapefile representing land cover of interest 
gl = MultiPolygon([shape(pol['geometry']) for pol in fiona.open('class3_aa.shp', 'r')]) 

#search area
areaKM2 = 20

#create empty spatial index
idx = index.Index()

#set initial search radius for buffer
areaM2 = areaKM2 * 1000000
r = (math.sqrt(areaM2/math.pi))

#create spatial index from gl
for i, shape in enumerate(gl):
    idx.insert(i, shape.bounds)

#query index for ids that intersect with buffer (will eventually have multiple points)
for point in traps:
        pt_buffer = shape(point['geometry']).buffer(r)
        intersect_ids = pt_buffer.intersection(idx)

しかし、私はTypeErrorを取得し続けます: 'Polygon'オブジェクトは呼び出し可能ではありません


1
空間インデックスは、交差点を実行するソフトウェアが認識していると作成するために空間インデックスを使用する(ユーザの観点から含有されない単一のエンティティ)積分データセットに対して透明なショートリストを迅速に知らせることによってと実際の交差点を実行します綿密な検査のために機能を検討する必要があり、明らかに交差点の近くにないソフトウェア。どのように作成するかは、ソフトウェアとデータ型によって異なります...より具体的なヘルプが必要な場合は、これらの点に関する詳細情報を提供してください。シェイプファイルの場合は、.shxファイルです。
マイケルスティムソン14年

4
.shxは空間インデックスではありません。これは、単に可変幅レコードのダイナミックアクセスオフセットファイルです。.sbn / .sbxはArcGISシェープファイルの空間インデックスのペアですが、それらの仕様はリリースされていません。
ビンス14年

1
また、.qixMapServerのはある/ GDAL / OGR / SpatiaLite クワッドインデックス
マイク・T

あなたのアイデアは、実際の空間インデックスを持たないSpatialiteにぴったりです。他のほとんどの形式は、空間インデックスをまったくサポートしていれば、透過的に行います。
user30184 14年

2
shapelyからインポートしTypeError: 'Polygon' object is not callableshape関数を、次の行で作成したPolygonオブジェクトで上書きするため、更新の例を取得し続けますfor i, shape in enumerate(gl):
。– user2856

回答:


12

それがその要点です。Rツリーを使用すると、非常に高速な最初のパスを作成でき、「偽陽性」のある結果セットが得られます(ジオメトリが正確に交差しない場合、境界ボックスが交差する場合があります)。次に、候補のセットを調べ(インデックスによってシェープファイルからそれらを取得)、たとえばShapelyを使用して数学的に正確な交差テストを行います。これは、PostGISなどの空間データベースで採用されている戦略とまったく同じです。


1
すてきなしゃれ(GiST)!GiSTは通常Bツリーのバリアントとして記述されますが、PostgresqlにはRツリーのGiST実装があります。wikiは必ずしも引用するための最良の参照ではありませんが、バウンディングボックス検索を説明するための素晴らしい図表があります。
MappaGnosis 14年

これは、別のデータベース・テーブルは、いくつかのSQLと画面キャプチャを示したとしても、R-ツリーをサポートしていないOGC GeoPackageについてのあなたのステップ2と3のように、このブログをR-treeインデックスを使用するためのマニュアルの方法学ぶ価値があることができopenjump.blogspot.fiを/ 2014/02 /…
user30184 14年

9

あなたはほとんどそれを手に入れましたが、あなたは小さなエラーを犯しました。バッファリングされたポイントのメソッドにintersectionインデックスを渡すのではなく、空間インデックスでメソッドを使用する必要がありますintersection。境界ボックスが重なるフィーチャのリストを見つけたら、バッファリングされたポイントが実際にジオメトリと交差するかどうかを確認する必要があります。

import fiona
from shapely.geometry import mapping
import rtree
import math

areaM2 = areaKM2 * 1000000
r = (math.sqrt(areaM2/math.pi))

# open both layers
with fiona.open('single_pt_speed_test.shp', 'r') as layer_pnt:
    with fiona.open('class3_aa.shp', 'r') as layer_land:

        # create an empty spatial index object
        index = rtree.index.Index()

        # populate the spatial index
        for fid, feature in layer_land.items():
            geometry = shape(feature['geometry'])
            idx.insert(fid, geometry.bounds)

        for feature in layer_pnt:
            # buffer the point
            geometry = shape(feature['geometry'])
            geometry_buffered = geometry.buffer(r)

            # get list of fids where bounding boxes intersect
            fids = [int(i) for i in index.intersection(geometry_buffered.bounds)]

            # access the features that those fids reference
            for fid in fids:
                feature_land = layer_land[fid]
                geometry_land = shape(feature_land['geometry'])

                # check the geometries intersect, not just their bboxs
                if geometry.intersects(geometry_land):
                    print('Found an intersection!')  # do something useful here

土地のクラスから最小距離内にあるポイントを見つけることに関心がある場合は、distance代わりにメソッドを使用できます(前のセクションから適切なセクションを交換します)。

for feature in layer_pnt:
    geometry = shape(feature['geometry'])

    # expand bounds by r in all directions
    bounds = [a+b*r for a,b in zip(geometry.bounds, [-1, -1, 1, 1])]

    # get list of fids where bounding boxes intersect
    fids = [int(i) for i in index.intersection(geometry_buffered.bounds)]

    for fid in fids:
        feature_land = layer_land[fid]
        geometry_land = shape(feature_land['geometry'])

        # check the geometries are within r metres
        if geometry.distance(geometry_land) <= r:
            print('Found a match!')

空間インデックスの作成に時間がかかり、これを数回以上行う場合は、インデックスをファイルにシリアル化することを検討する必要があります。ドキュメントにはこれを行う方法が記載されています:http : //toblerity.org/rtree/tutorial.html#serializing-your-index-to-a-file

次のように、ジェネレータを使用してバウンディングボックスをrtreeに一括読み込みすることもできます。

def gen(collection):
    for fid, feature in collection.items():
        geometry = shape(feature['geometry'])
        yield((fid, geometry.bounds, None))
index = rtree.index.Index(gen(layer_land))

2

はい、それがアイデアです。shapely、Fiona、およびgeopandasを使用したPythonでのrツリー空間インデックスの使用に関するこのチュートリアルからの抜粋を次に示します。

rツリーは、空間インデックスの最低レベルとして、個々のオブジェクトとその境界ボックス(「r」は「長方形」を意味します)を表します。次に、近くのオブジェクトを集約し、インデックスの次の上位レベルにある集約境界ボックスでそれらを表します。さらに高いレベルでは、rツリーはバウンディングボックスを集約し、すべてが1つの最上位バウンディングボックスにネストされるまで、バウンディングボックスで繰り返し表示します。検索するために、rツリーはクエリボックスを取得し、トップレベルから開始して、どのバウンディングボックスが交差するか(存在する場合)を確認します。次に、交差する各境界ボックスを展開し、その内部のどの子境界ボックスがクエリボックスと交差するかを確認します。これは、交差するすべてのボックスが最下位レベルまで検索されるまで再帰的に進行し、一致するオブジェクトを最下位レベルから返します。

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