i geopandas spaziali si uniscono estremamente lentamente


13

Sto usando il codice qui sotto per trovare un paese (e talvolta lo stato) per milioni di punti GPS. Il codice attualmente richiede circa un secondo per punto, che è incredibilmente lento. Lo shapefile è di 6 MB.

Ho letto che Geopandas usa le risorse per i join spaziali, rendendole incredibilmente efficienti, ma questo non sembra funzionare qui. Che cosa sto facendo di sbagliato? Speravo in circa mille punti al secondo o giù di lì.

Il file di forma e CSV possono essere scaricati qui (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

Il tuo collegamento dati è 404
Aaron

Risposte:


16

l'aggiunta dell'argomento op = 'entro' nella funzione sjoin velocizza drasticamente l'operazione punto-in-poligono.

Il valore predefinito è op = 'intersects', che immagino porterebbe anche a risultati corretti, ma è da 100 a 1000 volte più lento.


Per chiunque legga questo, ciò non significa che withinsia generalmente in qualche modo più veloce, leggi la risposta di nick_g di seguito.
inc42

7

La domanda chiede come sfruttare r-tree nei join spaziali geopandas e un altro risponditore sottolinea correttamente che è necessario utilizzare "entro" anziché "interseca". Tuttavia, puoi anche sfruttare un indice spaziale r-tree in geopandas mentre usi intersects/ intersection, come dimostrato in questo tutorial di r-tree geopandas :

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)]

5

Quello che sta succedendo qui è che solo il dataframe sulla destra viene inserito nell'indice rtree: https://github.com/geopandas/geopandas/blob/master/geopandas/tools/sjoin.py#L48-L55 Che per un op="intersects"run significherebbe che il poligono è stato inserito nell'indice, quindi per ogni punto, il poligono corrispondente viene trovato attraverso l'indice rtree.

Ma per op="within", i geodataframes sono capovolti poiché l'operazione è in realtà l'inverso di contains: https://github.com/geopandas/geopandas/blob/master/geopandas/tools/sjoin.py#L41-L43

Quindi quello che è successo quando hai cambiato opda op="intersects"a op="within"è che per ogni poligono, i punti corrispondenti vengono trovati attraverso l'indice rtree, che nel tuo caso ha velocizzato la query.


1
Hai usato URL non permanenti, potresti aggiornarli a una revisione specifica forse?
inc42
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.