geopandas espaciales unirse extremadamente lento

13

Estoy usando el siguiente código para encontrar un país (y, a veces, un estado) para millones de puntos GPS. El código actualmente toma aproximadamente un segundo por punto, que es increíblemente lento. El archivo de forma es de 6 MB.

Leí que las geopandas usan rtrees para uniones espaciales, lo que las hace increíblemente eficientes, pero esto no parece funcionar aquí. ¿Qué estoy haciendo mal? Esperaba mil puntos por segundo más o menos.

El archivo de forma y el csv se pueden descargar aquí (5 MB): https://www.dropbox.com/s/gdkxtpqupj0sidm/SpatialJoin.zip?dl=0

import pandas as pd
import geopandas as gpd
from geopandas import GeoDataFrame, read_file
from geopandas.tools import sjoin
from shapely.geometry import Point, mapping,shape
import time


#parameters
shapefile="K:/.../Shapefiles/Used/World.shp"
df=pd.read_csv("K:/.../output2.csv",index_col=None,nrows=20)# Limit to 20 rows for testing    

if __name__=="__main__":
    start=time.time()
    df['geometry'] = df.apply(lambda z: Point(z.Longitude, z.Latitude), axis=1)
    PointsGeodataframe = gpd.GeoDataFrame(df)
    PolygonsGeodataframe = gpd.GeoDataFrame.from_file(shapefile)
    PointsGeodataframe.crs = PolygonsGeodataframe.crs
    print time.time()-start
    merged=sjoin(PointsGeodataframe, PolygonsGeodataframe, how='left')
    print time.time()-start
    merged.to_csv("K:/01. Personal/04. Models/10. Location/output.csv",index=None)
    print time.time()-start
Alexis Eggermont
fuente
Su enlace de datos es 404
Aaron

Respuestas:

16

Agregar el argumento op = 'inside' en la función sjoin acelera dramáticamente la operación de punto en el polígono.

El valor predeterminado es op = 'intersecta', lo que supongo que también conduciría a un resultado correcto, pero es de 100 a 1000 veces más lento.

Alexis Eggermont
fuente
Para cualquiera que lea esto, esto no quiere decir que withines por lo general de alguna manera más rápida, la respuesta de nick_g Lea a continuación.
inc42
7

La pregunta pregunta cómo aprovechar el r-tree en uniones espaciales geopandas, y otro respondedor señala correctamente que debe usar 'dentro' en lugar de 'intersecta'. Sin embargo, también puede aprovechar un índice espacial de r-tree en geopandas mientras usa intersects/ intersection, como se demuestra en este tutorial de geopandas r-tree :

spatial_index = gdf.sindex
possible_matches_index = list(spatial_index.intersection(polygon.bounds))
possible_matches = gdf.iloc[possible_matches_index]
precise_matches = possible_matches[possible_matches.intersects(polygon)]
eos
fuente
5

Lo que probablemente está sucediendo aquí es que solo el marco de datos de la derecha se alimenta al índice rtree: https://github.com/geopandas/geopandas/blob/master/geopandas/tools/sjoin.py#L48-L55 Que para un op="intersects"ejecutar significaría que el Polígono se introdujo en el índice, por lo que para cada punto, el polígono correspondiente se encuentra a través del índice rtree.

Pero para op="within", los geodataframes se voltean ya que la operación es en realidad la inversa de contains: https://github.com/geopandas/geopandas/blob/master/geopandas/tools/sjoin.py#L41-L43

Entonces, lo que sucedió cuando cambió opde op="intersects"a op="within"es que para cada polígono, los puntos correspondientes se encuentran a través del índice rtree, que en su caso aceleró la consulta.

nick_g
fuente
1
Usó URL no permanentes, ¿podría actualizarlas a una revisión específica tal vez?
inc42