bergabung spasial geopanda sangat lambat

13

Saya menggunakan kode di bawah ini untuk menemukan negara (dan terkadang menyatakan) untuk jutaan titik GPS. Kode saat ini membutuhkan sekitar satu detik per titik, yang sangat lambat. Shapefile adalah 6 MB.

Saya membaca bahwa geopanda menggunakan rtrees untuk gabungan spasial, membuatnya sangat efisien, tetapi ini tampaknya tidak berfungsi di sini. Apa yang saya lakukan salah? Saya berharap untuk seribu poin per detik atau lebih.

Shapefile dan csv dapat diunduh di sini (5MB): 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
sumber
Tautan data Anda adalah 404
Aaron

Jawaban:

16

menambahkan argumen op = 'inside' dalam fungsi sjoin mempercepat operasi point-in-polygon secara dramatis.

Nilai default adalah op = 'berpotongan', yang saya kira juga akan mengarah pada hasil yang benar, tetapi 100 hingga 1000 kali lebih lambat.

Alexis Eggermont
sumber
Bagi siapa pun yang membaca ini, ini tidak berarti bahwa withinsecara umum entah bagaimana lebih cepat, baca jawaban nick_g di bawah ini.
termasuk42
7

Pertanyaan itu menanyakan bagaimana cara memanfaatkan r-tree dalam gabungan spasial geopanda, dan responden lain dengan benar menunjukkan bahwa Anda harus menggunakan 'di dalam' alih-alih 'berpotongan'. Namun, Anda juga dapat memanfaatkan indeks spasial r-tree di geopandas saat menggunakan intersects/ intersection, seperti yang ditunjukkan dalam tutorial r-tree geopandas ini :

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

Apa yang mungkin terjadi di sini adalah bahwa hanya kerangka data di sebelah kanan dimasukkan ke dalam indeks rtree: https://github.com/geopandas/geopandas/blob/master/geopandas/tools/sjoin.py#L48-L55 Yang mana untuk op="intersects"run berarti Poligon dimasukkan ke dalam indeks, jadi untuk setiap titik, poligon yang sesuai ditemukan melalui indeks rtree.

Tetapi untuk op="within", geodataframe dibalik karena operasi sebenarnya kebalikan dari contains: https://github.com/geopandas/geopandas/geobandas/blob/master/geopandas/tools/sjoin.py#L41-L43

Jadi apa yang terjadi ketika Anda beralih opdari op="intersects"ke op="within"adalah bahwa untuk setiap poligon, poin yang sesuai ditemukan melalui indeks rtree, yang dalam kasus Anda mempercepat kueri.

nick_g
sumber
1
Anda menggunakan URL tidak permanen, bisakah Anda memperbaruinya ke revisi tertentu?
inc42