编程语言
首页 > 编程语言> > Python 非调包实现K中心聚类算法

Python 非调包实现K中心聚类算法

作者:互联网

Python 非调包实现K中心聚类算法

文章目录


前言

终于结束一学期的学业,有时间静下心来学自己感兴趣的领域,写写博客记录学习心得了。
聚类是机器学习中经典的一类算法,大家广为熟知的是Kmeans算法,而K中心却少有听说,大多数机器学习书籍中也少有提到这个算法。
今天就来讲讲K中心聚类算法是怎么回事。

一、K中心聚类算法是什么?

1.K中心点聚类算法的基本思想为:

对于K中心点聚类算法,首先随意选择初始代表对象(或种子)。代表对象也被称为是中心点,其他对象则被称为非代表对象。
最初随机选择k个对象作为中心点,该算法反复地用非代表对象来代替代表对象,试图找出更好的中心点,以改进聚类的质量。

2.K中心聚类与Kmeans的主要区别:

初始化聚类中心上的不同,Kmeans是选择样本空间中随机坐标点作为中心,这些点并不一定就代表某个样本点对象;而K中心则是选择样本点对象作为聚类中心;
距离计算公式上的不同,Kmeans通常使用欧式距离,K中心则使用曼哈顿距离;
更新聚类中心上的不同,Kmeans使用簇内样本点求均值方式更新中心,K中心则是先产生中心点和非中心点的组合,然后求哪个组合的代价函数最小再决定新的中心。

3.K-中心点聚类算法流程描述:

输入:簇的数目k和包含n个对象的数据库
输出:k个簇,使得所有对象与其最近中心点的相异度总和最小
(1)任意选择k个对象作为初始的簇中心点
(2)Repeat
(3)指派每个剩余对象给离他最近的中心点所表示的簇
(4)Repeat
(5)选择一个未被选择的中心点
(6)Repeat
(7)选择一个未被选择过的非中心点对象Orandom
(8)计算用Orandom代替Oi的总代价并记录在S中
(9)Until 所有非中心点都被选择过
(10)Until 所有的中心点都被选择过
(11)If 在S中的所有非中心点代替所有中心点后的计算出总代价有小于0的存在,then找出S中的用非中心点替代中心点后代价最小的一个,并用该非中心点替代对应的中心点,形成一个新的k个中心点的集合;
(12)Until 没有再发生簇的重新分配,即所有的S都大于0

4.举例说明

假如空间中的五个点{ABCDE},各点之间的距离关系如表所示,根据所给的数据对其运行K中心点算法实现聚类划分(设K=2)。
在这里插入图片描述
(1)首先随机选取中心,以{AB}为例,则属于簇被分为{ACD}和{BE},分簇这一步其实分法有很多,这里只是为了分得均匀,答案不唯一。
(2)计算出以AB为中心的代价函数Cost(AB)=d(AC)+d(AD)+d(BE)=2+2+3=7,有必要一提的是这里代价函数的定义也有多种,K中心的目的就是为了找出和簇内其他点距离之和最小的点作为新的中心
(3)分别对中心{AB}和非中心{CDE}进行组合得出待计算代价的中心点集合{AC,AD,AE,BC,BD,BE},然后一一求这些中心组的代价函数,然后和原中心代价函数相减,得出最小值的那一组为新中心,例:Cost(AC)=d(AB)+d(AE)+d(CD)=5,Cost(AC)-Cost(AB)=-2。由于这题特殊,可以有很多组新中心。
(4)不断进行上面步骤直到代价差值不再减少。
PS:不懂还可以在参考一下K-中心点聚类算法(K-Medoide)

二、代码实现

import random
import numpy as np

class Kmedoid:
    def __init__(self, data, k):
    """
    data:训练数据,矩阵形式
    k:聚类个数
    """
        self.data = data
        self.k = k

    def randCent(self):  # 随机选取一个点
        random_index = random.randint(0, self.data.shape[0]-1)
        return random_index, self.data[random_index, :]

    def distance(self, vecA, vecB):  # 计算曼哈顿距离
        return sum(abs(vecA - vecB))

    def run(self):
        init_centers = []  # 初始化中心的列表
        init_indexs = []  # 被选中作为中心的点的下标
        while len(init_centers) < self.k:
            index, center = self.randCent()
            if index not in init_indexs:  # 保证选点不重复
                init_centers.append(center)
                init_indexs.append(index)
            else:
                continue

        while True:
            cluster_category = []  # 记录聚类结果
            for i in range(self.data.shape[0]):  # 遍历每一个点
                minv = np.inf  # 最小距离,初始为正无穷
                cluster_index = 0  # 所属簇的下标
                for index, center in enumerate(init_centers):  # 遍历每个中心
                    # 选取离得最近的中心作为归属簇
                    dist = self.distance(center, self.data[i, :])
                    if dist < minv:
                        minv = dist
                        cluster_index = index
                cluster_category.append(cluster_index)

            # 重新计算中心点
            new_indexs = [0 for i in range(len(init_centers))]  # 更新被选中作为中心的点的下标
            min_dists = [np.inf for i in range(len(init_centers))]  # 中心点对应最小距离
            for i in range(self.data.shape[0]):
                min_dist = 0  # 求与当前簇其他点的距离之和
                for j in range(self.data.shape[0]):  # 遍历每一个点
                    if cluster_category[i] == cluster_category[j]:  # 属于同一个簇才进行累加
                        min_dist += self.distance(self.data[i, :], self.data[j, :])
                if min_dist < min_dists[cluster_category[i]]:  # 保存数据到列表
                    min_dists[cluster_category[i]] = min_dist
                    new_indexs[cluster_category[i]] = i

            init_centers = []  # 新的聚类中心
            for index in new_indexs:
                init_centers.append(self.data[index, :])

            if new_indexs == init_indexs:  # 如果新的中心与上次相同则结束循环
                return cluster_category, init_centers
            else:
                init_indexs = new_indexs  # 更新聚类中心下标

总结

学习机器学习算法就要学习掌握其原理,并且最好自己用基本库实现一下,而不要光是使用第三方库调包的形式,机器学习是深度学习、强化学习的基础,万丈高楼平地起,基础不牢地动山摇,祝大家寒假愉快!

标签:中心,Python,self,算法,调包,init,中心点,聚类
来源: https://blog.csdn.net/weixin_43594279/article/details/112978464