Ich habe Code, mit dem ich feststelle, welche Shapely-Polygone / MultiPolygone sich mit einer Reihe von Shapely-LineStrings schneiden. Durch die Antworten auf diese Frage ist der Code von diesem gegangen:
import fiona
from shapely.geometry import LineString, Polygon, MultiPolygon, shape
# Open each layer
poly_layer = fiona.open('polygon_layer.shp')
line_layer = fiona.open('line_layer.shp')
# Convert to lists of shapely geometries
the_lines = [shape(line['geometry']) for line in line_layer]
the_polygons = [(poly['properties']['GEOID'], shape(poly['geometry'])) for poly in poly_layer]
# Check for Polygons/MultiPolygons that the LineString intersects with
covered_polygons = {}
for poly_id, poly in the_polygons:
for line in the_lines:
if poly.intersects(line):
covered_polygons[poly_id] = covered_polygons.get(poly_id, 0) + 1
wo jede mögliche Kreuzung überprüft wird, dazu:
import fiona
from shapely.geometry import LineString, Polygon, MultiPolygon, shape
import rtree
# Open each layer
poly_layer = fiona.open('polygon_layer.shp')
line_layer = fiona.open('line_layer.shp')
# Convert to lists of shapely geometries
the_lines = [shape(line['geometry']) for line in line_layer]
the_polygons = [(poly['properties']['GEOID'], shape(poly['geometry'])) for poly in poly_layer]
# Create spatial index
spatial_index = rtree.index.Index()
for idx, poly_tuple in enumerate(the_polygons):
_, poly = poly_tuple
spatial_index.insert(idx, poly.bounds)
# Check for Polygons/MultiPolygons that the LineString intersects with
covered_polygons = {}
for line in the_lines:
for idx in list(spatial_index.intersection(line.bounds)):
if the_polygons[idx][1].intersects(line):
covered_polygons[idx] = covered_polygons.get(idx, 0) + 1
Dabei wird der räumliche Index verwendet, um die Anzahl der Kreuzungsprüfungen zu verringern.
Mit den Shapefiles, die ich habe (ungefähr 4000 Polygone und 4 Zeilen), führt der ursprüngliche Code 12936 .intersection()
Überprüfungen durch und dauert ungefähr 114 Sekunden, um ausgeführt zu werden. Der zweite Code, der den räumlichen Index verwendet, führt nur 1816 .intersection()
Überprüfungen durch, die Ausführung dauert jedoch ungefähr 114 Sekunden.
Die Ausführung des Codes zum Erstellen des räumlichen Index dauert nur 1-2 Sekunden, sodass die 1816-Überprüfungen im zweiten Codeteil ungefähr genauso lange dauern wie die 12936-Überprüfungen im ursprünglichen Code (seit dem Laden von Shapefiles und das Konvertieren in Shapely-Geometrien sind in beiden Codeteilen gleich.
Ich kann keinen Grund erkennen, warum der räumliche Index die .intersects()
Überprüfung länger dauern würde, daher weiß ich nicht, warum dies geschieht.
Ich kann nur denken, dass ich den RTree-Raumindex falsch verwende. Gedanken?
quelle
intersects()
Methode dauert länger, wenn der räumliche Index verwendet wird (siehe Zeitvergleich oben), weshalb ich nicht sicher bin, ob ich den räumlichen Index falsch verwende. Nach dem Lesen der Dokumentation und der verlinkten Beiträge denke ich, dass ich es bin, aber ich hatte gehofft, jemand könnte darauf hinweisen, wenn ich es nicht wäre.Nur um die Antwort von mgri zu ergänzen.
Es ist wichtig zu verstehen, was ein räumlicher Index ist ( wie man eine Begrenzungsbox für Shapely & Fiona richtig implementiert? ). Mit meinem Beispiel in Wie man effizient bestimmt, welche von Tausenden von Polygonen sich mit einem Linienstreifen schneiden
Mit den Polygonen können Sie einen räumlichen Index erstellen
Grenzen des räumlichen Index (Polygongrenzen in grün)
Oder mit den LineStrings
Grenzen des räumlichen Index (LineString rot gebunden)
Jetzt durchlaufen Sie nur die Geometrien, die sich mit Ihrer aktuellen Geometrie überschneiden können (in Gelb).
Ich verwende hier den räumlichen LineStrings-Index (die Ergebnisse sind dieselben, aber mit Ihrem Beispiel von 4000 Polygonen und 4 Linien ....).
Sie können auch einen Generator verwenden ( example.py )
Sie können das GeoPandas-Skript sjoin.py untersuchen , um die Verwendung von Rtree zu verstehen .
Es gibt viele Lösungen, aber vergessen Sie das nicht
quelle
Bearbeiten: Um diese Antwort zu verdeutlichen, habe ich fälschlicherweise geglaubt, dass alle Kreuzungstests ungefähr gleich lange gedauert haben. Das ist nicht der Fall. Der Grund, warum ich nicht die Geschwindigkeit erreicht habe, die ich von der Verwendung eines räumlichen Index erwartet hatte, ist, dass die Auswahl der Kreuzungstests diejenigen war, die überhaupt am längsten gedauert haben.
Wie Gen und Mgri bereits gesagt haben, ist ein räumlicher Index kein Zauberstab. Obwohl der räumliche Index die Anzahl der Kreuzungstests, die von 12936 auf nur 1816 durchgeführt werden mussten, reduzierte, waren die Tests von 1816 der Test, dessen Berechnung die meiste Zeit in Anspruch nahm.
Der räumliche Index wird korrekt verwendet, aber die Annahme, dass jeder Schnittpunkttest ungefähr die gleiche Zeit benötigt, ist falsch. Die für den Kreuzungstest erforderliche Zeit kann stark variieren (0,05 Sekunden gegenüber 0,000007 Sekunden).
quelle