Tengo un código que estoy usando para determinar qué Polígono Shapely / MultiPolygons se cruzan con una serie de Shapely LineStrings. A través de las respuestas a esta pregunta, el código ha pasado de esto:
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
donde se verifica cada posible intersección, para esto:
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
donde el índice espacial se usa para reducir el número de verificaciones de intersección.
Con los archivos de forma que tengo (aproximadamente 4000 polígonos y 4 líneas), el código original realiza 12936 .intersection()
comprobaciones y tarda aproximadamente 114 segundos en ejecutarse. La segunda pieza de código que usa el índice espacial realiza solo 1816 .intersection()
comprobaciones, pero también tarda aproximadamente 114 segundos en ejecutarse.
El código para construir el índice espacial solo tarda de 1 a 2 segundos en ejecutarse, por lo que las comprobaciones de 1816 en la segunda parte del código tardan casi la misma cantidad de tiempo en realizarse que las comprobaciones de 12936 en el código original (desde la carga de shapefiles y la conversión a geometrías Shapely es lo mismo en ambas partes del código).
No veo ninguna razón por la que el índice espacial haga que la .intersects()
verificación tarde más, por lo que no sé por qué sucede esto.
Solo puedo pensar que estoy usando el índice espacial RTree incorrectamente. Pensamientos?
fuente
intersects()
método lleva más tiempo cuando se usa el índice espacial (consulte la comparación de tiempo anterior), por lo que no estoy seguro de si estoy usando el índice espacial incorrectamente. Al leer la documentación y las publicaciones vinculadas, creo que sí, pero esperaba que alguien pudiera señalar si no fuera así.Solo para agregar a mgri respuesta.
Es importante comprender qué es un índice espacial ( ¿Cómo implementar correctamente un cuadro de límites para Shapely y Fiona? ). Con mi ejemplo en Cómo determinar eficientemente cuál de los miles de polígonos se cruzan con una cadena lineal
Puedes crear un índice espacial con los polígonos
Límites del índice espacial (límites de polígonos en verde)
O con los LineStrings
Límites del índice espacial (LineString encuadernado en rojo)
Ahora, itera solo a través de las geometrías que tienen la posibilidad de cruzarse con su geometría actual (en amarillo)
Utilizo aquí el índice espacial LineStrings (los resultados son los mismos pero con su ejemplo de 4000 polígonos y 4 líneas ...).
También puedes usar un generador ( ejemplo.py )
Puede examinar el script GeoPandas sjoin.py para comprender el uso de Rtree .
Hay muchas soluciones pero no olvides que
fuente
Editar: para aclarar esta respuesta, creí incorrectamente que todas las pruebas de intersección tomaron aproximadamente la misma cantidad de tiempo. Este no es el caso. La razón por la que no obtuve la velocidad que esperaba al usar un índice espacial es que la selección de las pruebas de intersección son las que tomaron más tiempo en primer lugar.
Como ya han dicho gene y mgri, un índice espacial no es una varita mágica. Aunque el índice espacial redujo el número de pruebas de intersección que debían realizarse desde 12936 hasta solo 1816, las pruebas de 1816 son la prueba que, en primer lugar, tomó la gran mayoría del tiempo para calcular.
El índice espacial se está utilizando correctamente, pero la suposición de que cada prueba de intersección toma aproximadamente la misma cantidad de tiempo es lo incorrecto. El tiempo requerido por la prueba de intersección puede variar mucho (0.05 segundos versus 0.000007 segundos).
fuente