纯Python实现聚类:按欧氏距离将数据点分配至最近质心
Kmeans单点分配实现方案
你现有代码存在两个核心问题,导致无法完成聚类:
- 聚类列表初始化错误:
[[]] * 6会生成6个指向同一内存地址的空列表,修改任意一个子列表所有子列表都会同步变化;且你只有4个质心,不需要初始化6个子列表。 - 缺少距离比较、匹配最近质心的逻辑:当前代码仅把所有距离追加到总列表中,没有关联距离和对应质心的序号,也没有筛选最小距离。
实现逻辑
按照Kmeans的簇分配步骤,按以下流程写即可:
- 为每个质心创建独立的空列表,作为对应簇的存储容器,子列表数量和质心数量完全一致。
- 逐个遍历数据点,计算当前点到每一个质心的欧氏距离,把所有距离按质心顺序存入临时列表。
- 找到临时距离列表中最小值对应的索引,该索引就是当前点所属簇的序号。
- 把当前点追加到对应序号的簇列表中,所有点遍历完成后返回聚类结果即可。
注:比较距离大小时可以省略
math.sqrt()计算,因为平方根是单调递增运算,不影响距离大小的判断结果,能省一点计算量;加上也完全不影响结果正确性。
修正后可直接运行的代码
import math def cluster_mydata(centroids, points): # 为每个质心初始化独立的空簇,索引和质心顺序一一对应 clusters = [[] for _ in range(len(centroids))] for point in points: # 记录当前点到所有质心的距离 distance_list = [] for centroid in centroids: euclidean_dist = math.sqrt( (point[0] - centroid[0]) ** 2 + (point[1] - centroid[1]) ** 2 ) distance_list.append(euclidean_dist) # 找到距离最近的质心对应的索引 nearest_idx = distance_list.index(min(distance_list)) # 将点划入对应簇 clusters[nearest_idx].append(point) return clusters
测试示例
用你给出的样例数据测试:
if __name__ == "__main__": sample_centroids = [[12,3],[0,-8],[-28,20],[1,1]] sample_points = [(31,3),(10,9),(1,0),(-2,-5)] print(cluster_mydata(sample_centroids, sample_points))
输出结果为:
[[(31, 3), (10, 9)], [(-2, -5)], [], [(1, 0)]]
结果完全符合要求:第1个子列表存距离第1个质心最近的点,第2个对应第2个质心,以此类推,示例中没有点距离第3个质心(-28,20)最近,因此对应子列表为空。
内容的提问来源于stack exchange,提问作者maria
相关产品推荐
相关产品推荐

