将点分配给最近的多边形
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
,这意味着该点在两个多边形中。
所以我的问题是,有没有办法很好地处理这个问题?即:
- 忽略包含不明确的任何内容
- 更好:“如果该点更接近其中一个几何图形,则它属于那个几何图形”
- 还有其他方法吗?
感谢您对此的任何见解!
所以,我找到了一种方法来回答我的问题。可能有比这更好的东西,如果我的答案看起来很麻烦,我将不胜感激。
想法是在多边形周围创建一个缓冲区,这样缓冲的多边形就会吸收点,然后 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
我有这种情况,我想检测应该包含在几何特征边界上的元素,但由于各种原因,这些点状对象可以在几何特征的内部或外部“看到”几何学。内部部分不是问题,因为我希望使用“包含”作为一种方法。所以,我所做的是 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
,这意味着该点在两个多边形中。
所以我的问题是,有没有办法很好地处理这个问题?即:
- 忽略包含不明确的任何内容
- 更好:“如果该点更接近其中一个几何图形,则它属于那个几何图形”
- 还有其他方法吗?
感谢您对此的任何见解!
所以,我找到了一种方法来回答我的问题。可能有比这更好的东西,如果我的答案看起来很麻烦,我将不胜感激。
想法是在多边形周围创建一个缓冲区,这样缓冲的多边形就会吸收点,然后 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