K-means Python实现

K-means Python实现

import numpy as np
import random
import matplotlib.pyplot as plt

"""
1 从n个向量对象任意选择k个向量作为初始聚类中心
2 根据在步骤(1)中设置的k个向量(中心对象向量),计算每个对象与这k个中心对象各自的距离
3 对于步骤(2)中的计算,任何一个向量与这个k个向量都有一个距离,有的远有的近,把这个向量与距离它最近的中心向量对象归在一个类簇中
4 重新计算每个类簇的中心向量位置
5 重复(3)(4),直到类簇聚类方案中的向量归类变化极少时为止。例如:一次迭代后,只有少于1%的向量还在发生类簇聚类漂移,可认为分为完成。
"""

fig, ax = plt.subplots()


def find_centroids(points: list,
                   k: int) -> list:
    """
    从points中随机获取k个点作为质心\n
    :param points:  候选的点
    :param k:       选取的点的数量
    :return:        np.ndarray
    """
    return random.sample(points, k)


def calculate_distance(vecA: np.ndarray,
                       vecB: np.ndarray) -> float:
    """
    计算向量vecA和向量vecB之间的欧氏距离\n
    :param vecA:
    :param vecB:
    :return:
    """
    return np.sqrt(np.sum(np.square(vecA - vecB)))


def min_distance(points: np.ndarray,
                 centroid_list: list) -> dict:
    """
    计算data_get中的元素与centroidList中k个聚类中心的欧式距离\n
    找出距离最小的, 将该元素加入相应的聚类中\n
    :param points:
    :param centroid_list:
    :return:
    """
    #
    #

    cluster_dict = dict()                                   # 用字典存储聚类结果
    for element in points:
        vecA = np.array(element)                            # 转换成数组形式
        flag = 0                                            # 元素分类标记,记录与相应聚类距离最近的那个类
        minDis = float("inf")                               # 初始化为最大值

        for i in range(len(centroid_list)):
            vecB = np.array(centroid_list[i])
            distance = calculate_distance(vecA, vecB)       # 两向量间的欧式距离
            if distance < minDis:
                minDis = distance
                flag = i                                    # 保存与当前item距离最近的那个聚类的标记

        if flag not in cluster_dict.keys():                 # 簇标记不存在,进行初始化
            cluster_dict[flag] = list()
        cluster_dict[flag].append(element)                  # 加入相应的类中

    return cluster_dict                                     # 返回新的聚类结果


def get_centroids(cluster_dict: dict) -> list:
    """
    求聚类中心即求解每列的均值
    :param cluster_dict:
    :return:
    """
    centroid_list = list()
    for key_ in cluster_dict.keys():
        centroid = np.mean(np.array(cluster_dict[key_]), axis=0)  #
        centroid_list.append(centroid)

    return list(centroid_list)


def calculate_Var(cluster_dict: dict,
                  centroid_list: list) -> float:
    """
    计算聚类间的均方误差\n
    将类中各个向量与聚类中心的距离进行累加求和\n
    :param cluster_dict:
    :param centroid_list:
    :return:
    """
    sum_ = 0.0
    for key_ in cluster_dict.keys():
        vecA = np.array(centroid_list[key_])
        distance = 0.0
        for item in cluster_dict[key_]:
            vecB = np.array(item)
            distance += calculate_distance(vecA, vecB)
        sum_ += distance

    return sum_


def show_cluster(centroid_list: list,
                 cluster_list: dict):
    """
    画聚类结果
    :param centroid_list:
    :param cluster_list:
    :return:
    """

    global ax
    colorMark = ['or', 'ob', 'og', 'ok', 'oy', 'ow']                    # 元素标记
    centroidMark = ['dr', 'db', 'dg', 'dk', 'dy', 'dw']                 # 聚类中心标记
    for key_ in cluster_list.keys():
        # 画聚类中心
        cluster_centroids, = ax.plot(centroid_list[key_][0], centroid_list[key_][1], centroidMark[key_], markersize=12)
        for item in cluster_list[key_]:
            points, = ax.plot(item[0], item[1], colorMark[key_])        # 画类下的点
    ax.legend([cluster_centroids, points], ['centroids', 'points'])


# data = [[0.0, 0.0], [3.0, 8.0], [2.0, 2.0], [1.0, 1.0], [5.0, 3.0],
#         [4.0, 8.0], [6.0, 3.0], [5.0, 4.0], [6.0, 4.0], [7.0, 5.0]]

num_of_points   = 200                                       # 点的数量
num_of_classes  = 5                                         # 簇的数量
data            = np.random.rand(num_of_points, 2)*20       # 随机生成的点
epsilon         = 0.00001                                   # 当连续两次聚类结果差距小于0.0001时,迭代结束
pause           = 1.0                                       # 两帧之间的间隔, 单位秒


if __name__ == '__main__':

    centroidList = find_centroids(list(data), num_of_classes)   # 随机获取3个聚类中心
    clusterDict = min_distance(data, centroidList)              # 第一次聚类迭代
    newVar = calculate_Var(clusterDict, centroidList)           # 计算均方误差值,通过新旧均方误差来获得迭代终止条件
    oldVar = -epsilon                                           # 初始化均方误差
    while abs(newVar - oldVar) >= epsilon:
        ax.cla()
        centroidList = get_centroids(clusterDict)               # 获得新的聚类中心
        clusterDict = min_distance(data, centroidList)          # 新的聚类结果
        oldVar = newVar
        newVar = calculate_Var(clusterDict, centroidList)
        show_cluster(centroidList, clusterDict)                 # 展示聚类结果
        plt.pause(pause)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

对象被抛出

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值