如何分割numpy坐标点列表的两类点簇并分别计算均值
问题背景
现有存储二维坐标点对的numpy数组,需要对空间近邻的点分组计算簇均值,固定返回2个簇的中心点。
第一组测试样例
输入点集:
[[214,295], [215, 294], [229, 226], [229, 227]]
当前基于Z-score的实现输出为:
[[222.0, 260.5], [214.0, 295.0], [229.0, 226.0]]
预期输出为两组近邻点各自的均值:
- 近邻组1([214,295]、[215,294])均值:
[214.5, 294.5] - 近邻组2([229,226]、[229,227])均值:
[229.0, 226.5]
要求最终固定返回2个点,不出现3个及以上结果,需要确认是否要重新调整Z-score计算逻辑。
第二组测试样例
输入点集:[[95, 132], [96, 132], [94, 133], [134, 239], [95, 131]]
当前实现输出为:
[[ 95. 132.], [134. 239.]]
需求:当[134,239]点位附近聚集大量点时,需要更鲁棒的双点簇分割方法。
现有实现代码
import numpy as np from scipy import stats tempList = np.array([[214,295], [215, 294],[229, 226], [229, 227]]) z= stats.zscore(tempList, axis=0) z = list([abs(x)<1 and abs(y)<1 for x,y in z]) newList = tempList[[not x for x in z]] tempList = tempList[z] newList = np.concatenate([[tempList.mean(axis=0)], newList]) print(newList)
解决方案
不需要调整Z-score计算逻辑,Z-score本身是基于单维度全局分布的异常值过滤方法,完全不感知二维空间中点的距离邻近关系,第一组数据出错的原因是全局均值刚好落在两个点簇的中间位置,被Z-score判定为正常点,最终输出了多余的中心点。
针对固定分割2个点簇的需求,直接使用指定簇数为2的K-Means聚类即可,该方法基于空间距离划分簇,对两个簇点数差异较大、点聚集的场景鲁棒性远高于全局Z-score过滤。
修正后实现代码
import numpy as np from sklearn.cluster import KMeans # 测试第一组数据 tempList1 = np.array([[214,295], [215, 294],[229, 226], [229, 227]]) kmeans = KMeans(n_clusters=2, n_init=10, random_state=42) kmeans.fit(tempList1) print("第一组簇中心:\n", kmeans.cluster_centers_) # 输出 [[214.5 294.5] [229. 226.5]],完全匹配预期结果 # 测试第二组数据 tempList2 = np.array([[95, 132], [96, 132], [94, 133], [134, 239], [95, 131]]) kmeans.fit(tempList2) print("第二组簇中心:\n", kmeans.cluster_centers_) # 输出 [[ 95. 132.] [134. 239.]],和现有正确结果一致
如果场景中存在远离两个主簇的极端离群点,可以在聚类前增加一层基于距离的离群点过滤;如果无法100%确定点簇数量固定为2,也可以替换为DBSCAN密度聚类,自动识别高密度点簇后取规模最大的2个簇计算均值。但固定返回2个簇的场景下,指定簇数的K-Means是实现最简单、效果最稳定的方案。
内容的提问来源于stack exchange,提问作者peter teoh
相关产品推荐
相关产品推荐

