将点分配给最近的多边形

Assign point to closest polygon

我有这种情况,我想检测应该包含在几何特征边界上的元素,但由于各种原因,这些点状对象可以在几何特征的内部或外部“看​​到”几何学。内部部分不是问题,因为我希望使用“包含”作为一种方法。所以,我所做的是 buffer 我拥有的几何图形,以便“捕获”边界外的元素。但这也是一个问题。事实上,缓冲可能意味着一个元素属于两个几何图形,而实际上它们只能在一个几何图形中。

举个例子(虽然很幼稚,但还是能说明问题)

import geopandas
import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt
from shapely.geometry import Point
from geopandas import datasets, GeoDataFrame, read_file
from geopandas.tools import overlay
from shapely.geometry import Polygon, LineString, Point
s = geopandas.GeoSeries(
    [
        Point(1.1, 1.1),
        Point(0.1, 1.1),
    ],
)
s2 = geopandas.GeoSeries(
    [
        Polygon([(0, 0), (1, 1), (0, 1)]),
        Polygon([(1.25, 1), (2, 2), (1.25, 2)]),
        
    ],
    index=range(1, 3),
)

envgdf1 = geopandas.GeoDataFrame(geometry=gpd.GeoSeries(s2))
envgdf2 = geopandas.GeoDataFrame(geometry=gpd.GeoSeries(s))

envgdf1 = envgdf1.rename_geometry('Object')
envgdf2 = envgdf2.rename_geometry('Point')

把三角形想象成我的物体,把黑点想象成实际上应该在这些三角形中的任何一个上的这些物体。正如我上面所解释的,我缓冲三角形以吞没这些点:

envgdf1['buffered_object'] = envgdf1['Object'].buffer(0.3)
envgdf1 = envgdf1.set_geometry('buffered_object')

结果是

被视为数据框:

df = gpd.sjoin(envgdf1,envgdf2, how="inner", op='contains')

                                       Object  \
1  POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....   
1  POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....   
2  POLYGON ((1.25000 1.00000, 2.00000 2.00000, 1....   

                                     buffered_object  index_right  
1  POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ...            1  
1  POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ...            0  
2  POLYGON ((0.95000 1.00000, 0.95000 2.00000, 0....            0  


您可以注意到同一对象有两行index_right = 0,这意味着该点在两个多边形中。

所以我的问题是,有没有办法很好地处理这个问题?即:

  1. 忽略包含不明确的任何内容
  2. 更好:“如果该点更接近其中一个几何图形,则它属于那个几何图形”
  3. 还有其他方法吗?

感谢您对此的任何见解!

所以,我找到了一种方法来回答我的问题。可能有比这更好的东西,如果我的答案看起来很麻烦,我将不胜感激。

想法是在多边形周围创建一个缓冲区,这样缓冲的多边形就会吸收点,然后 sjoin 但保留点。通常的连接会忽略一个人想要包含的几何形状。所以我们开始吧:

而不是

df = gpd.sjoin(envgdf1,envgdf2, how="inner", op='contains')

我们将确保通过使用 savedgeom:

来保持积分
envgdf2['savedgeom'] = envgdf2.geometry
df = gpd.sjoin(envgdf1,envgdf2, how="inner", op='contains')

这导致:

 Object  \
1  POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....   
1  POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....   
2  POLYGON ((1.25000 1.00000, 2.00000 2.00000, 1....   

                                     buffered_object  index_right  \
1  POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ...            1   
1  POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ...            0   
2  POLYGON ((0.95000 1.00000, 0.95000 2.00000, 0....            0   

                 savedgeom  
1  POINT (0.10000 1.10000)  
1  POINT (1.10000 1.10000)  
2  POINT (1.10000 1.10000)  

现在,我们可以确定每个点到不同多边形的距离:

df.crs = "EPSG:4326"
df['dist'] = gpd.GeoSeries(df['Object']).distance(gpd.GeoSeries(df['savedgeom']))

给出:

Object  \
1  POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....   
1  POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....   
2  POLYGON ((1.25000 1.00000, 2.00000 2.00000, 1....   

                                     buffered_object  index_right  \
1  POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ...            1   
1  POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ...            0   
2  POLYGON ((0.95000 1.00000, 0.95000 2.00000, 0....            0   

                 savedgeom      dist  
1  POINT (0.10000 1.10000)  0.100000  
1  POINT (1.10000 1.10000)  0.141421  
2  POINT (1.10000 1.10000)  0.150000  

因为我们的目标是将一个点与最近的多边形相匹配,我们可以简单地做到

df = df.sort_values("dist", ascending=True).groupby(["index_right"]).first().reset_index()

给出:

 index_right                                             Object  \
0            0  POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....   
1            1  POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....   

                                     buffered_object                savedgeom  \
0  POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ...  POINT (1.10000 1.10000)   
1  POLYGON ((-0.30000 0.00000, -0.30000 1.00000, ...  POINT (0.10000 1.10000)   

       dist  
0  0.141421  
1  0.100000