如何对聚类后的点集批量计算凸包并导出指定格式结果?
批量生成聚类簇的凸包顶点并整理为指定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]]
问题分析
- 原循环假设簇编号是从0开始的连续整数,但实际DBSCAN生成的簇编号可能不连续(如示例中的4、60、90、147),导致大部分簇未被遍历。
- 未将簇编号与对应凸包顶点关联,无法直接生成目标格式的DataFrame。
- 未处理簇内点数不足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
相关产品推荐
相关产品推荐

