机器学习教程 之 K-means聚类:简单有效的聚类方法

聚类是指将数据集中的样本划分为若干个不相交的子集,子集内元素的相似度大,而子集间元素的相似度小。K-means(K均值)聚类是一种非常简单有效、同时解释性也非常强的算法,看了一些相似内容的博客,将这一内容说的颇为复杂,这里将以尽量简单简介的方式,将这一内容介绍给初学者学习

一、相似度即距离

如开题所说,聚类是通过判断样本间的相似度来进行的,这种相似度我们通常使用样本属性间的距离来衡量,最常用的距离是闵可夫斯距离,定义如下:

这里写图片描述
这里写图片描述
这里写图片描述

其中的p是自定义的参数,当p为2是闵可夫斯基距离即为欧式距离,K-means聚类采用的便是这种距离方案。

二、K-means算法

K-means的核心思想在于,对聚类算法划分得到的k个类别C = {C1,C2,…,Ck}有最小化的平方误差E

这里写图片描述

其最小化的平房误差求解方案在实际编程时,我们采用循环迭代的方式


	1.确定聚类个数k
	2.从数据集中随机选取k个样本	,作为初始均值向量
	3.计算数据集中的样本与各个均值向量的距离,划为距离最近的类
	4.根据上面的公式计算新的均值向量	
	5.如果均值向量和之前相比未变则结束聚类,
	  若不想等则回到第三步重复计算	

完整代码地址:https://github.com/LiangjunFeng/Machine-Learning/blob/master/7.K-means.py
模块程序讲解如下:

创建数据

def creatData():
    data1 = numpy.mat(numpy.random.randint(0,12,size=(2,50)))
    data2 = numpy.mat(numpy.random.randint(8,20,size=(2,50)))
    data = numpy.hstack((data1,data2)).T
      
    label1 = numpy.mat(numpy.zeros(50)).T
    label2 = numpy.mat(numpy.ones(50)).T
    label = numpy.vstack((label1,label2))
    return data,label

预备函数

def minkowskiDistance(vector1,vector2,p=2):  #闵斯基距离函数
    vector1 = numpy.ravel(vector1)
    vector2 = numpy.ravel(vector2)
    length,distance = len(vector1),0
    for i in range(length):
        distance += abs(vector1[i] - vector2[i])**p
    return distance**(1.0/p)

def randomInt(minimum,maximum):  #在给定范围内产生一个整数,用于随机选取初始均值向量
    return random.randrange(minimum,maximum,1)

K-mens类

class K_means:
    def __init__(self):
        self._classes = 0   #聚类类别数
        self._averageVectorList = []     #均值向量列表
        self._classSetList = []          #样本分类列表
     
    def setUp(self,data,number):         #类建立
        self._classes = number
        self._averageVectorList = [0]*self._classes
        for i in range(self._classes):
            self._classSetList.append([])
    
    def randomVector(self,data):         #随机选择初始均值向量
        for i in range(self._classes):
            self._averageVectorList[i] = data[randomInt(0,data.shape[0]),:]
            
    def classifiy(self,data):           #根据闵斯基距离分类
        samples,attributes = data.shape
        for i in range(samples):
            k = 0
            for j in range(self._classes):
                if minkowskiDistance(data[i,:],self._averageVectorList[k]) > minkowskiDistance(data[i,:],self._averageVectorList[j]):
                    k = j
            self._classSetList[k].append(i)
    
    def renewAverageVector(self,data):   #根据分类数据更新均值向量
        for i in range(self._classes):
            sum = 0
            for j in range(len(self._classSetList[i])):
                sum += data[self._classSetList[i][j],:]
            self._averageVectorList[i] = numpy.ravel(sum/len(self._classSetList[i]))
            
    def compare(self,vector):            #用于比较新旧均值向量是否相等
        if vector == []:
            return False
        for i in range(len(vector)):
            if not (self._averageVectorList[i] == vector[i]).all():
                    return False
        return True
           
    def clustering(self,data,number,limits = 100):  #聚类函数
        self.setUp(data,number)
        self.randomVector(data)
        oldAverageVector,times = [],0
        while (not self.compare(oldAverageVector)) and (times < limits):
            oldAverageVector = self._averageVectorList.copy()
            self._classSetList.clear()
            for i in range(self._classes):
                self._classSetList.append([])
            self.classifiy(data)
            self.renewAverageVector(data)
            print(times)
            times += 1
        

测试主函数

if __name__ == '__main__':    
    data,label = creatData()
    
    C = K_means()
    C.clustering(data,2)
    
    for i in range(len(C._classSetList[0])):
        p1=plt.scatter(data[C._classSetList[0][i],0],data[C._classSetList[0][i],1],marker='x',color='g') 
    for i in range(len(C._classSetList[1])):
        p2=plt.scatter(data[C._classSetList[1][i],0],data[C._classSetList[1][i],1],marker='+',color='r')
    plt.show()

结果:
计算一次
这里写图片描述
计算三次
这里写图片描述
计算七次,最终结果
这里写图片描述

三、更多资源下载

微信搜索“老和山算法指南”获取更多下载链接与技术交流群
在这里插入图片描述
有问题可以私信博主,点赞关注的一般都会回复,一起努力,谢谢支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Liangjun_Feng

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

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

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

打赏作者

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

抵扣说明:

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

余额充值