Вычислить расстояние до ближайшего объекта с помощью Geopandas
Я ищу, чтобы сделать эквивалент ArcPy Создать Рядом Таблицу использование Geopandas / Shapely. Я очень новичок в Geopandas и Shapely и разработал методологию, которая работает, но мне интересно, есть ли более эффективный способ сделать это.
у меня есть два набора данных точечных файлов - центроиды блока переписи и рестораны. Я ищу, чтобы найти, для каждого центроида блока переписи, расстояние до ближайшего ресторана. Нет никаких ограничений с точки зрения того же ресторан-ближайший ресторан на несколько кварталов.
причина, по которой это становится немного сложнее для меня, заключается в том, что функция расстояния Geopandas вычисляет поэлементно, сопоставления, основанные на индексе. Поэтому моя общая методология состоит в том, чтобы превратить файл ресторанов в многоточечный файл, а затем установить индекс файла блоков для всех одинаковое значение. Тогда все центроиды блоков и рестораны имеют одинаковый индекс значение.
import pandas as pd
import geopandas as gpd
from shapely.geometry import Polygon, Point, MultiPoint
теперь читайте в блоке Centroid и ресторане Шейп-файлы:
Blocks=gpd.read_file(BlockShp)
Restaurants=gpd.read_file(RestaurantShp)
поскольку функция расстояния Geopandas вычисляет расстояние по элементам, я преобразую ресторан GeoSeries в многоточечный GeoSeries:
RestMulti=gpd.GeoSeries(Restaurants.unary_union)
RestMulti.crs=Restaurants.crs
RestMulti.reset_index(drop=True)
затем я установил индекс для блоков равным 0 (то же значение, что и для ресторанов multipoint) в качестве работы для elementwise расчета.
Blocks.index=[0]*len(Blocks)
наконец, я использую функцию расстояния Geopandas для рассчитайте расстояние до ближайшего ресторана для каждого блока центроид.
Blocks['Distance']=Blocks.distance(RestMulti)
пожалуйста, предложите любые предложения о том, как любой аспект этого может быть улучшен. Я не привязан к использованию Geopandas или Shapely, но я ищу альтернативу ArcPy.
Спасибо за помощь!
1 ответов
если я правильно понимаю вашу проблему, блоки и рестораны могут иметь очень разные размеры. По этой причине, вероятно, это плохой подход, чтобы попытаться заставить формат таблицы путем переиндексирования.
Я бы просто зациклился на блоках и получил минимальное расстояние до ресторанов (как и предлагал @shongololo).
Я собираюсь быть немного более общим (потому что у меня уже записан этот код) и делать расстояние от точек до строк, но тот же код должен работать от точек к точкам или от полигонов к полигонам. Я начну с GeoDataFrame
для точек, и я создам новый столбец, который имеет минимальное расстояние до линий.
%matplotlib inline
import matplotlib.pyplot as plt
import shapely.geometry as geom
import numpy as np
import pandas as pd
import geopandas as gpd
lines = gpd.GeoSeries(
[geom.LineString(((1.4, 3), (0, 0))),
geom.LineString(((1.1, 2.), (0.1, 0.4))),
geom.LineString(((-0.1, 3.), (1, 2.)))])
# 10 points
n = 10
points = gpd.GeoSeries([geom.Point(x, y) for x, y in np.random.uniform(0, 3, (n, 2))])
# Put the points in a dataframe, with some other random column
df_points = gpd.GeoDataFrame(np.array([points, np.random.randn(n)]).T)
df_points.columns = ['Geometry', 'Property1']
points.plot()
lines.plot()
теперь получите расстояние от точек до линий и сохраните только минимальное расстояние для каждой точки (см. ниже для версии с apply)
min_dist = np.empty(n)
for i, point in enumerate(points):
min_dist[i] = np.min([point.distance(line) for line in lines])
df_points['min_dist_to_lines'] = min_dist
df_points.head(3)
что дает
Geometry Property1 min_dist_to_lines
0 POINT (0.2479424516236574 2.944916965334865) 2.621823 0.193293
1 POINT (1.465768457667432 2.605673714922998) 0.6074484 0.226353
2 POINT (2.831645235202689 1.125073838462032) 0.657191 1.940127
---- редактировать ----
(взято из github вопрос) с помощью apply
лучше и более соответствует тому, как вы это сделаете в pandas
:
def min_distance(point, lines):
return lines.distance(point).min()
df_points['min_dist_to_lines'] = df_points.geometry.apply(min_distance, df_lines)