如何使用 geopanda 或 shapely 在同一地理数据框中找到最近的点

How to use geopanda or shapely to find nearest point in same geodataframe

我有一个地理数据框,显示约 25 个位置,表示为点几何。我试图想出一个脚本来遍历每个点,识别最近的位置并 returns 最近位置的名称和距离。

如果我在 shapely.ops 库中使用 nearest_points(geom1, geom2) 有不同的地理数据框,我可以很容易地做到这一点。但是,我所有的位置都存储在一个地理数据框中。我正在尝试循环,这就是我遇到问题的地方

这是我的示例文件:

geofile = gpd.GeoDataFrame([[0, 'location A', Point(55, 55)],
                            [1, 'location B', Point(66, 66)],
                            [2, 'Location C', Point(99, 99)],
                            [3, 'Location D', Point(11, 11)]],
                           columns=['ID','Location','geometry'])

这是我创建的循环,但没有用。

for index, row in geofile.iterrows():
    nearest_geoms=nearest_points(row, geofile)
    print('location:' + nearest_geoms[0])
    print('nearest:' + nearest_geoms[1])
    print('-------')

我收到这个错误:

AttributeError: 'Series' object has no attribute '_geom'

但是我认为我的问题超出了错误原因,因为不知何故我必须排除我正在循环的行,因为它会自动 return 作为最近的位置,因为它是那个位置。

我对一个地点的最终结果如下:

([0,'location A','location B', '5 miles', Point(55,55)], columns=['ID','Location','Nearest', 'Distance',geometry'])

Shapely 的 nearest_points 函数比较匀称的几何图形。要将单个 Point 几何图形与多个其他 Point 几何图形进行比较,您可以使用 .unary_union 与生成的 MultiPoint 几何图形进行比较。是的,在每一行操作中,删除相应的点,这样它就不会与自身进行比较。

import geopandas as gpd
from shapely.geometry import Point
from shapely.ops import nearest_points

df = gpd.GeoDataFrame([[0, 'location A', Point(55,55)], 
                       [1, 'location B', Point(66,66)],
                       [2, 'Location C', Point(99,99)],
                       [3, 'Location D' ,Point(11,11)]], 
                      columns=['ID','Location','geometry'])
df.insert(3, 'nearest_geometry', None)

for index, row in df.iterrows():
    point = row.geometry
    multipoint = df.drop(index, axis=0).geometry.unary_union
    queried_geom, nearest_geom = nearest_points(point, multipoint)
    df.loc[index, 'nearest_geometry'] = nearest_geom

导致

    ID  Location    geometry        nearest_geometry
0   0   location A  POINT (55 55)   POINT (66 66)
1   1   location B  POINT (66 66)   POINT (55 55)
2   2   Location C  POINT (99 99)   POINT (66 66)
3   3   Location D  POINT (11 11)   POINT (55 55)

这是另一种基于scipy.spatial.distance.cdist 的方法。 iterrows 通过使用 numpy 掩码数组来避免。

import geopandas as gpd
from scipy.spatial import distance
import numpy.ma as ma
from shapely.geometry import Point
import numpy as np

df = gpd.GeoDataFrame([[0, 'location A', Point(55,55)], 
                       [1, 'location B', Point(66,66)],
                       [2, 'Location C', Point(99,99)],
                       [3, 'Location D' ,Point(11,11)]], 
                      columns=['ID','Location','geometry'])

coords = np.stack(df.geometry.apply(lambda x: [x.x, x.y]))
distance_matrix = ma.masked_where((dist := distance.cdist(*[coords] * 2)) == 0, dist)
df["closest_ID"] = np.argmin(distance_matrix, axis=0)
df = df.join(df.set_index("ID").geometry.rename("nearest_geometry"), on="closest_ID")
df.drop("closest_ID", axis=1)

# Out:
   ID    Location               geometry           nearest_geometry
0   0  location A  POINT (55.000 55.000)  POINT (66.00000 66.00000)
1   1  location B  POINT (66.000 66.000)  POINT (55.00000 55.00000)
2   2  Location C  POINT (99.000 99.000)  POINT (66.00000 66.00000)
3   3  Location D  POINT (11.000 11.000)  POINT (55.00000 55.00000)

多个邻居的泛化

由于 distance_matrix 包含所有点对之间距离的完整信息,因此很容易将这种方法推广到任意数量的邻居。例如,如果我们有兴趣为每个点找到 N_NEAREST = 2 个邻居,我们可以对距离矩阵进行排序(使用 np.argsort,而不是像以前那样选择 np.argmin)和 select对应的列数:

nearest_id_cols = list(map("nearest_id_{}".format, range(1, N_NEAREST + 1)))
nearest_geom_cols = list(map("nearest_geometry_{}".format, range(1, N_NEAREST + 1)))
df[nearest_id_cols] = np.argsort(distance_matrix, axis=1)[:, :N_NEAREST]
df[nearest_geom_cols] = df[nearest_id_cols].applymap(
                             lambda x: df.set_index("ID").geometry[x])

# out:
   ID    Location                  geometry  nearest_id_1  nearest_id_2  \
0   0  location A  POINT (55.00000 55.00000)             1             2   
1   1  location B  POINT (66.00000 66.00000)             0             2   
2   2  Location C  POINT (99.00000 99.00000)             1             0   
3   3  Location D  POINT (11.00000 11.00000)             0             1   

  nearest_geometry_1 nearest_geometry_2  
0       POINT (66 66)       POINT (99 99)  
1       POINT (55 55)       POINT (99 99)  
2       POINT (66 66)       POINT (55 55)  
3       POINT (55 55)       POINT (66 66)