геопанда пространственное соединение крайне медленно

13

Я использую код ниже, чтобы найти страну (а иногда и штат) для миллионов точек GPS. Код в настоящее время занимает около одной секунды на точку, что невероятно медленно. Шейп-файл 6 МБ.

Я читал, что геопанда использует деревья для пространственных объединений, что делает их невероятно эффективными, но здесь это, похоже, не работает. Что я делаю неправильно? Я надеялся на тысячу очков в секунду или около того.

Шейп-файл и csv можно скачать здесь (5 МБ): 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
Алексис Эггермонт
источник
Ваша ссылка данных 404
Аарон

Ответы:

16

добавление аргумента op = 'inside' в функцию sjoin значительно ускоряет операцию точка-полигон.

Значением по умолчанию является op = 'intersects', которое, я думаю, также приведет к правильному результату, но медленнее в 100-1000 раз.

Алексис Эггермонт
источник
Для тех, кто читает это, это не значит, что withinэто вообще как-то быстрее, прочитайте ответ nick_g ниже.
inc42
7

Вопрос состоит в том, как использовать r-дерево в пространственных объединениях геопанд, и другой респондент правильно указывает, что вы должны использовать «внутри», а не «пересекается». Однако вы также можете воспользоваться пространственным индексом r-дерева в геопандах, используя intersects/ intersection, как показано в этом руководстве по r-дереву геопанд :

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

Скорее всего, здесь происходит только то, что только фрейм данных справа подается в индекс rtree: https://github.com/geopandas/geopandas/blob/master/geopandas/tools/sjoin.py#L48-L55, который для op="intersects"Выполнение означало бы, что полигон был введен в индекс, поэтому для каждой точки соответствующий полигон находится через индекс rtree.

Но для op="within"геоданных кадры перевернуты, так как операция на самом деле обратная contains: https://github.com/geopandas/geopandas/blob/master/geopandas/tools/sjoin.py#L41-L43

Итак, что произошло, когда вы переключились opс op="intersects"на op="within"на то, что для каждого многоугольника соответствующие точки находятся через индекс rtree, что в вашем случае ускорило запрос.

nick_g
источник
1
Вы использовали непостоянные URL, можете ли вы обновить их до определенной ревизии?
inc42