首页 > 解决方案 > 仅当它们在附近时才从点列表创建多边形

问题描述

我有一个点列表(经度和纬度),以及它们在地理数据框中的相关点几何。所有点都应该能够细分为单独的多边形,因为这些点通常聚集在几个区域中。我想做的是有某种算法循环点并检查前一个点和当前点之间的距离。如果距离足够小,它会将这些点组合在一起。这个过程会一直持续到当前点离得太远。它将从这些接近的点中生成一个多边形,然后使用下一组点继续该过程。

gdf
longitude   latitude    geometry
0   -76.575249  21.157229   POINT (-76.57525 21.15723)
1   -76.575035  21.157453   POINT (-76.57503 21.15745)
2   -76.575255  21.157678   POINT (-76.57526 21.15768)
3   -76.575470  21.157454   POINT (-76.57547 21.15745)
5   -112.973177 31.317333   POINT (-112.97318 31.31733)
... ... ... ...
2222    -113.492501 47.645914   POINT (-113.49250 47.64591)
2223    -113.492996 47.643609   POINT (-113.49300 47.64361)
2225    -113.492379 47.643557   POINT (-113.49238 47.64356)
2227    -113.487443 47.643142   POINT (-113.48744 47.64314)
2230    -105.022627 48.585669   POINT (-105.02263 48.58567)

所以在上面的数据中,前 4 个点将被组合在一起并变成一个多边形。然后,它会移动到下一组,依此类推。每组点的间距不均匀,即下一组可能是 7 对点,接下来可能是 3 对。理想情况下,最终输出将是另一个地理数据帧,它只是一堆多边形。

标签: pythonpandasgeopandasshapely

解决方案


您可以尝试 DBSCAN 聚类,因为它会自动找到最佳聚类数,并且您可以指定点之间的最大距离 (ε)。

使用您的示例,该算法识别两个集群。

import pandas as pd
from sklearn.cluster import DBSCAN

df = pd.DataFrame(
    [
        [-76.575249, 21.157229, (-76., 21.15723)],
        [-76.575035, 21.157453, (-76.57503, 21.15745)],
        [-76.575255, 21.157678, (-76.57526, 21.15768)],
        [-76.575470, 21.157454, (-76.57547, 21.15745)],
        [-112.973177, 31.317333, (-112.97318, 31.31733)],
        [-113.492501, 47.645914, (-113.49250, 47.64591)],
        [-113.492996, 47.643609, (-113.49300, 47.64361)],
        [-113.492379, 47.643557, (-113.49238, 47.64356)],
        [-113.487443, 47.643142, (-113.48744, 47.64314)],
        [-105.022627, 48.585669, (-105.02263, 48.58567)]
    ], columns=["longitude", "latitude", "geometry"])

clustering = DBSCAN(eps=0.3, min_samples=4).fit(df[['longitude','latitude']].values)
gdf = pd.concat([df, pd.Series(clustering.labels_, name='label')], axis=1)
print(gdf)
gdf.plot.scatter(x='longitude', y='latitude', c='label')

    longitude   latitude                geometry  label
0  -76.575249  21.157229       (-76.0, 21.15723)      0
1  -76.575035  21.157453   (-76.57503, 21.15745)      0
2  -76.575255  21.157678   (-76.57526, 21.15768)      0
3  -76.575470  21.157454   (-76.57547, 21.15745)      0
4 -112.973177  31.317333  (-112.97318, 31.31733)     -1 # not in cluster
5 -113.492501  47.645914   (-113.4925, 47.64591)      1
6 -113.492996  47.643609    (-113.493, 47.64361)      1
7 -113.492379  47.643557  (-113.49238, 47.64356)      1
8 -113.487443  47.643142  (-113.48744, 47.64314)      1
9 -105.022627  48.585669  (-105.02263, 48.58567)     -1 # not in cluster

如果我们将随机数据添加到您的数据集中,运行聚类算法,并过滤掉那些不在聚类中的数据点,您就会更清楚地了解它是如何工作的。

import numpy as np
rng = np.random.default_rng(seed=42)
arr2 = pd.DataFrame(rng.random((3000, 2)) * 100, columns=['latitude', 'longitude'])
randdf = pd.concat([df[['latitude', 'longitude']], arr2]).reset_index()
clustering = DBSCAN(eps=1, min_samples=4).fit(randdf[['longitude','latitude']].values)
labels =  pd.Series(clustering.labels_, name='label')
gdf = pd.concat([randdf[['latitude', 'longitude']], labels], axis=1)

subgdf = gdf[gdf['label']> -1]
subgdf.plot.scatter(x='longitude', y='latitude', c='label', colormap='viridis', figsize=(20,10))

print(gdf['label'].value_counts())
-1     2527
 16      10
 3        8
 10       8
 50       8
       ... 
 57       4
 64       4
 61       4
 17       4
 0        4
Name: label, Length: 99, dtype: int64

DBSCAN 聚类图仅显示匹配的聚类

从这个数据框中获取聚类点会相对简单。像这样的东西:

subgdf['point'] = subgdf.apply(lambda x: (x['latitude'], x['longitude']), axis=1)
subgdf.groupby(['label'])['point'].apply(list)

label
0     [(21.157229, -76.575249), (21.157453, -76.5750...
1     [(47.645914, -113.492501), (47.643609, -113.49...
2     [(46.67210037270342, 4.380376578722878), (46.5...
3     [(85.34030732681661, 23.393948586534073), (86....
4     [(81.40203846660347, 16.697291990770392), (82....
                            ...                        
93    [(61.419880354359925, 23.25522624430636), (61....
94    [(50.893415175135424, 90.70863269095085), (52....
95    [(88.80586950148697, 81.17523712192651), (88.6...
96    [(34.23624333000541, 40.8156668231013), (35.86...
97    [(16.10456828199399, 67.41443008931344), (15.9...
Name: point, Length: 98, dtype: object

尽管您可能需要进行某种排序以确保在绘制多边形时连接最近的点。

类似的问题

来自 sklearn 的 DBSCAN


推荐阅读