web-dev-qa-db-ja.com

shapelyによるポリゴン交差の高速化

多数のポリゴン(〜100000)があり、通常のグリッドセルとの交差面積を計算するスマートな方法を見つけようとしています。

現在、シェイプリーを使用して(コーナー座標に基づいて)ポリゴンとグリッドセルを作成しています。次に、単純なforループを使用して、各ポリゴンを調べ、近くのグリッドセルと比較します。

ポリゴン/グリッドセルを説明するほんの小さな例です。

from shapely.geometry import box, Polygon
# Example polygon 
xy = [[130.21001, 27.200001], [129.52, 27.34], [129.45, 27.1], [130.13, 26.950001]]
polygon_shape = Polygon(xy)
# Example grid cell
gridcell_shape = box(129.5, -27.0, 129.75, 27.25)
# The intersection
polygon_shape.intersection(gridcell_shape).area

(ところで:グリッドセルの寸法は0.25x0.25で、ポリゴンは最大で1x1です)

実際、これは個々のポリゴン/グリッドセルのコンボで非常に高速で、約0.003秒です。ただし、このコードを大量のポリゴン(それぞれが数十個のグリッドセルと交差する可能性がある)で実行すると、マシン上で約15分以上(交差するグリッドセルの数に応じて最大30分以上)かかりますが、これは受け入れられません。残念ながら、ポリゴンの交差点のコードを記述して重複領域を取得する方法がわからない。ヒントはありますか? shapelyに代わるものはありますか?

37
HyperCube

Rtree を使用して、ポリゴンが交差する可能性のあるグリッドセルを識別することを検討してください。この方法で、lat/lonsの配列で使用されるforループを削除できます。これはおそらく遅い部分です。

コードを次のように構成します。

from shapely.ops import cascaded_union
from rtree import index
idx = index.Index()

# Populate R-tree index with bounds of grid cells
for pos, cell in enumerate(grid_cells):
    # assuming cell is a shapely object
    idx.insert(pos, cell.bounds)

# Loop through each Shapely polygon
for poly in polygons:
    # Merge cells that have overlapping bounding boxes
    merged_cells = cascaded_union([grid_cells[pos] for pos in idx.intersection(poly.bounds)])
    # Now do actual intersection
    print poly.intersection(merged_cells).area
56
Mike T

The Shapely User Manual は古くなっていますが、2013/2014以降、ShapelyはSTRtreeクラスで strtree.py を使用しています。私はそれを使用しましたが、うまくいくようです。

Docstringからの抜粋は次のとおりです。

STRtreeは、Sort-Tile-Recursiveアルゴリズムを使用して作成されるRツリーです。 STRtreeは、初期化パラメーターとしてジオメトリオブジェクトのシーケンスを取ります。初期化後、クエリメソッドを使用して、これらのオブジェクトに対して空間クエリを作成できます。

>>> from shapely.geometry import Polygon
>>> polys = [ Polygon(((0, 0), (1, 0), (1, 1))), Polygon(((0, 1), (0, 0), (1, 0))), Polygon(((100, 100), (101, 100), (101, 101))) ]
>>> s = STRtree(polys)
>>> query_geom = Polygon(((-1, -1), (2, 0), (2, 2), (-1, 2)))
>>> result = s.query(query_geom)
>>> polys[0] in result
True
16
Phil