Geopandas räumliche Verbindung extrem langsam

12

Ich verwende den folgenden Code, um ein Land (und manchmal einen Bundesstaat) für Millionen von GPS-Punkten zu finden. Der Code benötigt derzeit ungefähr eine Sekunde pro Punkt, was unglaublich langsam ist. Das Shapefile ist 6 MB groß.

Ich habe gelesen, dass Geopandas rtrees für räumliche Verknüpfungen verwenden, was sie unglaublich effizient macht, aber das scheint hier nicht zu funktionieren. Was mache ich falsch? Ich habe auf tausend Punkte pro Sekunde gehofft.

Das Shapefile und die CSV können hier heruntergeladen werden (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
quelle

Antworten:

16

Das Hinzufügen des Arguments op = 'within' in der sjoin-Funktion beschleunigt die Point-in-Polygon-Operation erheblich.

Der Standardwert ist op = 'intersects', was meines Erachtens ebenfalls zu einem korrekten Ergebnis führen würde, aber 100- bis 1000-mal langsamer ist.

Alexis Eggermont
quelle
Für jeden, der dies liest, bedeutet dies nicht, dass withines im Allgemeinen irgendwie schneller ist. Lesen Sie dazu die Antwort von nick_g weiter unten.
Inc42
7

In der Frage wird gefragt, wie Sie die Vorteile von R-Tree in räumlichen Geopanda-Joins nutzen können. Ein anderer Responder weist korrekt darauf hin, dass Sie 'inside' anstelle von 'intersects' verwenden sollten. Sie können jedoch auch einen räumlichen R-Tree-Index in Geopandas verwenden, während Sie intersects/ verwenden intersection. Dies wird in diesem R-Tree-Tutorial für Geopandas veranschaulicht :

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
quelle
5

Was hier wahrscheinlich vor sich geht, ist, dass nur der rechte Datenrahmen in den rtree-Index eingespeist wird: https://github.com/geopandas/geopandas/blob/master/geopandas/tools/sjoin.py#L48-L55 Which for an op="intersects"run würde bedeuten, dass das Polygon in den Index eingespeist wurde, sodass für jeden Punkt das entsprechende Polygon durch den rtree-Index gefunden wird.

Aber für op="within"die geodataframes da der Betrieb umgedreht werden , ist eigentlich das Gegenteil von contains: https://github.com/geopandas/geopandas/blob/master/geopandas/tools/sjoin.py#L41-L43

Also , was passiert , wenn Sie die geschaltete opvon op="intersects"zu op="within"ist , dass für jedes Polygon, werden die entsprechenden Punkte durch den RTREE Index gefunden, die in Ihrem Fall die Abfrage beschleunigt.

nick_g
quelle
1
Sie haben nicht permanente URLs verwendet. Können Sie diese möglicherweise auf eine bestimmte Revision aktualisieren?
Inc42