【问题标题】:How to use geopanda or shapely to find nearest point in same geodataframe如何使用 geopanda 或 shapely 在同一地理数据框中找到最近的点
【发布时间】:2019-10-24 12:33:06
【问题描述】:

我有一个显示约 25 个位置的地理数据框,表示为点几何。我正在尝试编写一个脚本来遍历每个点,识别最近的位置并返回最近位置的名称和距离。

如果我使用 shapely.ops 库中的最近点(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'

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

我对一个位置的最终结果如下:

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

【问题讨论】:

    标签: python gis geopandas shapely


    【解决方案1】:

    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)
    

    【讨论】:

    • 谢谢克里斯托夫。我不知道 unary_union。很有帮助。
    • 我们可以使用这种方法不包括 1 个而是 2 个最近的点吗?就像在 k 中最近的一样
    【解决方案2】:

    这是基于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)并选择相应的列数:

    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)  
    

    【讨论】:

    • 不错!对于较大的数据集应该更快。干杯
    猜你喜欢
    • 1970-01-01
    • 2018-02-20
    • 2012-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    • 2018-09-06
    相关资源
    最近更新 更多