SDUWH2019-2020寒假python实训--my_kmeans

本文详细介绍了K-means与K-means++两种聚类算法的Python实现过程,包括如何初始化聚类中心、计算样本点到聚类中心的距离、更新类别标签及中心点位置,直至算法收敛。同时,文中还提供了可视化的结果展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

# kmeans 算法
import numpy as np
import matplotlib.pyplot as plt

def my_kmeans(input_data, k=3, show_flag=False):
    # input_data = [[1, 5], [2, 4], [4, 1], [5, 0], [7, 6], [6, 7]]
    input_data_np = np.array(input_data)
    x, y = input_data_np[:,0], input_data_np[:,1]
    index_cls = []
    while index_cls.__len__() < k:
        n = np.random.randint(0, input_data_np.shape[0], 1)
        if not n in index_cls:
            index_cls.append(n[0])
    point_cls = input_data_np[np.array(index_cls)]
    num = 1
    while True:
        # 2. 更新样本点类别
        # 通过计算样本点到聚类中的使用欧式距离的平方(x1-x2)^2 + (y1-y2)^2
        dis_cls = np.array([list(np.sum((input_data_np - i) ** 2, axis=1)) for i in point_cls])
        # 3. 计算样本点新类别
        # 选取每一列上的最小值的索引,作为这个样本点的类别
        new_tag_samples = np.argmin(dis_cls, axis=0)
        # 添加显示的部分
        if show_flag:
            plt.figure(num)
            num += 1
            for i in range(k):
                plt.scatter(x[np.array(new_tag_samples) == i], y[np.array(new_tag_samples) == i])
        # 4. 计算新类中心
        # 计算新的类别中心
        new_point_cls = np.array([list(np.average(input_data_np[new_tag_samples == i], axis=0)) for i in range(k)])
        # 5. 计算新类中心的样本类别,做判断,如果类别发生了变化,计算更新类别,如果不变化了,那么就停止
        # 可以比较两个类的中心是否满足一定条件,(一般算和小与一定的值,不建议使用相等判断)
        sum_cls_point_dis = np.sum((new_point_cls - point_cls) ** 2)
        # 可以比较样本的类别变化,如果样本类别没有变化了,那就停止
        if sum_cls_point_dis < 0.05:
            break
        else:
            point_cls = new_point_cls
    if show_flag:
        plt.show()
    return new_point_cls,new_tag_samples



def my_kmeanspp(input_data, k=3, show_flag=False):
    # input_data = [[1, 5], [2, 4], [4, 1], [5, 0], [7, 6], [6, 7]]
    input_data_np = np.array(input_data)
    x, y = input_data_np[:,0], input_data_np[:,1]
    # 改成选择相距最远的点作为中心点
    point_cls = []
    # print(np.random.randint(0, input_data_np.shape[0], 1))
    tmp = input_data_np[np.random.randint(0, input_data_np.shape[0], 1)[0],:]
    # print(tmp)
    point_cls.append(list(tmp))
    # print(point_cls)
    # 计算第二个点,就是获取离类中心点最远的点
    while point_cls.__len__()<k:
        samples_dis_cls = np.array([list(np.sum((input_data_np - i) ** 2, axis=1)) for i in point_cls])
        samples_dis_cls_min = np.min(samples_dis_cls,axis=0)
        index_max_dis_sample = np.argmax(samples_dis_cls_min)
        point_cls.append(list(input_data_np[index_max_dis_sample]))
    print(point_cls)
    point_cls = np.array(point_cls)
    num = 1
    while True:
        # 2. 更新样本点类别
        # 通过计算样本点到聚类中的使用欧式距离的平方(x1-x2)^2 + (y1-y2)^2
        dis_cls = np.array([list(np.sum((input_data_np - i) ** 2, axis=1)) for i in point_cls])
        # 3. 计算样本点新类别
        # 选取每一列上的最小值的索引,作为这个样本点的类别
        new_tag_samples = np.argmin(dis_cls, axis=0)
        # 添加显示的部分
        if show_flag:
            plt.figure(num)
            num += 1
            for i in range(k):
                plt.scatter(x[np.array(new_tag_samples) == i], y[np.array(new_tag_samples) == i])
        # 4. 计算新类中心
        # 计算新的类别中心
        new_point_cls = np.array([list(np.average(input_data_np[new_tag_samples == i], axis=0)) for i in range(k)])
        # 5. 计算新类中心的样本类别,做判断,如果类别发生了变化,计算更新类别,如果不变化了,那么就停止
        # 可以比较两个类的中心是否满足一定条件,(一般算和小与一定的值,不建议使用相等判断)
        sum_cls_point_dis = np.sum((new_point_cls - point_cls) ** 2)
        # 可以比较样本的类别变化,如果样本类别没有变化了,那就停止
        if sum_cls_point_dis < 0.05:
            break
        else:
            point_cls = new_point_cls
    if show_flag:
        plt.show()
    return new_point_cls,new_tag_samples



# 测试封装好的函数
input_data = [[1, 5], [2, 4], [4, 1], [5, 0], [7, 6], [6, 7]]
# 使用散点图显示出来
# x = np.array(input_data)[:,0]  # 二维数组的第1列
# y = np.array(input_data)[:,1]  # 二维数组的第2列

# plt.scatter(x,y)
# plt.scatter(x-1,y-1)
# plt.show()

cls_point, tag_samples = my_kmeanspp(input_data,3)
print(input_data)
print(cls_point)
print(tag_samples)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

KingoKing

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

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

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

打赏作者

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

抵扣说明:

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

余额充值