使用Geopandas计算到最近特征的距离

2024-04-29 15:32:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我想用Geopandas/Shapely来做类似ArcPy Generate Near Table的工作。我对Geopandas很陌生,Shapely开发了一种有效的方法,但我想知道是否有一种更有效的方法。

我有两个点文件数据集-人口普查块质心和餐厅。我在寻找,对于每一个人口普查街区的中心,距离它最近的餐馆的距离。同一家餐厅是多个街区内距离最近的餐厅,没有任何限制。

这对我来说变得更复杂的原因是Geopandas Distance function根据索引计算元素级匹配。因此,我的一般方法是将餐厅文件转换为多点文件,然后将块文件的索引设置为相同的值。然后所有的块质心和餐厅都有相同的索引值。

import pandas as pd
import geopandas as gpd
from shapely.geometry import Polygon, Point, MultiPoint

现在读入方块形心和餐厅形状文件:

Blocks=gpd.read_file(BlockShp)
Restaurants=gpd.read_file(RestaurantShp)

由于Geopandas distance函数按元素计算距离,因此我将餐厅GeoSeries转换为多点GeoSeries:

RestMulti=gpd.GeoSeries(Restaurants.unary_union)
RestMulti.crs=Restaurants.crs
RestMulti.reset_index(drop=True)

然后我将块的索引设置为0(与餐厅多点的值相同),作为元素计算的解决方案。

Blocks.index=[0]*len(Blocks)

最后,我使用Geopandas距离函数计算每个块质心到最近餐馆的距离。

Blocks['Distance']=Blocks.distance(RestMulti)

请就如何改进这方面提出任何建议。我不喜欢使用Geopandas或Shapely,但我想学习ArcPy的替代品。

谢谢你的帮助!


Tags: 文件方法import元素距离餐厅geopandasarcpy
2条回答

您的代码缺少详细信息,args = (df_lines)

def min_distance(point, lines):
    return lines.distance(point).min()

df_points['min_dist_to_lines'] = df_points.geometry.apply(min_distance, args=(df_lines,))# Notice the change to this line

如果我正确理解你的问题,街区和餐馆的规模可能会有很大的不同。因此,尝试通过重新编制索引强制转换为表格式可能是一种不好的方法。

我只需绕着街区走一圈,就可以得到到餐馆的最小距离(就像@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()

enter image description here

现在获取点到线的距离,并且只保存每个点的最小距离(请参见下面的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)

编辑:至少从2019年10月4日起,熊猫的变化似乎需要在最后一个代码块中使用args参数输入不同的内容:

df_points['min_dist_to_lines'] = df_points.geometry.apply(min_distance, args=(df_lines,))

相关问题 更多 >