You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对聚类后的点集批量计算凸包并导出指定格式结果?

批量生成聚类簇的凸包顶点并整理为指定DataFrame

问题背景

现有包含经纬度与DBSCAN聚类簇编号的DataFrame,示例数据如下:

Latitude    Longitude   cluster-db
2   35.793020   -110.388760     90
32  32.842108   -193.565837     60
33  36.800923   -110.566971     4
34  31.896220   -99.551749     147

需求为:为每个簇计算凸包边界顶点,生成包含簇编号和对应顶点坐标字符串的DataFrame,示例格式如下:

cluster    Perimeter 
1          35.793020   -110.388760, 32.842108   -193.565837, 36.800923   -110.566971  

原尝试代码仅能得到第一个簇的结果:

from scipy.spatial import ConvexHull
import matplotlib.pyplot as plt

z=[] #HULL simplices coordinates will be appended here

for i in range (0,num_clusters-1):
    dfq=data_conv[data_conv['cluster-db']==i]
    Y = np.array(dfq[['Latitude', 'Longitude']])
    hull = ConvexHull(Y)
    plt.plot(Y[:, 1],Y[:, 0],  'o')
    z.append(Y[hull.vertices,:].tolist())
    for simplex in hull.simplices:
        ploted=plt.plot( Y[simplex, 1], Y[simplex, 0],'k-',c='m')

z

[[34.79267702, -109.3900481],
 [35.78415582, -101.39016576],
 [34.7959, -104.3892],
 [37.792889, -104.38547],
 [38.79321, -110.388667],
 [31.79231003, -103.38955313]]

问题分析

  1. 原循环假设簇编号是从0开始的连续整数,但实际DBSCAN生成的簇编号可能不连续(如示例中的4、60、90、147),导致大部分簇未被遍历。
  2. 未将簇编号与对应凸包顶点关联,无法直接生成目标格式的DataFrame。
  3. 未处理簇内点数不足3个的情况(ConvexHull要求至少3个点才能计算凸包),会引发报错。

解决方案代码

from scipy.spatial import ConvexHull
import numpy as np
import pandas as pd

# 初始化存储结果的列表
result_list = []

# 获取所有唯一的簇编号(避免假设连续编号)
unique_clusters = data_conv['cluster-db'].unique()

for cluster_id in unique_clusters:
    # 提取当前簇的经纬度数据
    cluster_data = data_conv[data_conv['cluster-db'] == cluster_id]
    coords = np.array(cluster_data[['Latitude', 'Longitude']])
    
    # 处理点数不足的情况:少于3个点无法生成凸包,直接保留所有点作为边界
    if len(coords) < 3:
        perimeter_points = coords
    else:
        # 计算凸包并获取顶点
        hull = ConvexHull(coords)
        perimeter_points = coords[hull.vertices, :]
    
    # 将顶点坐标转换为指定的字符串格式:"lat1 lon1, lat2 lon2, ..."
    perimeter_str = ", ".join([f"{lat:.6f} {lon:.6f}" for lat, lon in perimeter_points])
    
    # 将簇编号和顶点字符串加入结果列表
    result_list.append({'cluster': cluster_id, 'Perimeter': perimeter_str})

# 转换为目标DataFrame
result_df = pd.DataFrame(result_list)
# 可选:按簇编号排序
result_df = result_df.sort_values('cluster').reset_index(drop=True)

print(result_df.head())

关键说明

  • 遍历实际存在的簇编号:通过unique()获取所有簇ID,避免遗漏不连续的簇。
  • 异常处理:针对簇内点数少于3的情况直接保留所有点,防止ConvexHull报错。
  • 格式转换:用字符串拼接将顶点坐标整理为需求的格式,确保输出符合示例要求。
  • 可视化部分(可选):如果需要保留绘图,可在循环内添加原有的绘图代码,不影响结果生成。

内容的提问来源于stack exchange,提问作者JEG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 14:10:37