美文网首页
K均值聚类及代码实现

K均值聚类及代码实现

作者: Leo蓝色 | 来源:发表于2018-12-27 18:11 被阅读19次

    KMeans聚类

    在聚类算法中,最出名的应该就是k均值聚类(KMeans)了,几乎所有的数据挖掘/机器学习书籍都会介绍它,有些初学者还会将其与KNN等混淆。k均值是一种聚类算法,属于无监督学习的一种,而KNN是有监督学习/分类学习的一种。
    聚类:顾名思义,就是讲某些相似的事物聚在一起,形成一个类。这里就涉及到几个概念
    1.如何表示一个事物?通常我们会准备好一个数据集,里面是我们的数据,每一行代表的都是一个数据,每一列是一个数据的一种特征。比如经典的分类数据集 iris(鸢尾花数据),每一行代表的是每一朵花,每一朵花都有花萼长度,花萼宽度,花瓣长度,花瓣宽度 4个特征,即有4列特征。
    2.如何度量事物间的距离?我们拿到每一个数据的特征值之后,需要根据实际情况来进行两种数据之间的计算,常用的方法是欧氏距离、马氏距离、余弦距离等。
    3.按照什么样的过程进行聚类?这里就涉及到具体的算法了,目前聚类大致有几个比较流行的方法:基于划分、基于层次、基于密度、基于网络。这里的K均值就属于基于划分的方法,后续会继续写其余几种方法的代表算法。
    4.如何能判断聚类过程结束呢?当每一种类别中的数据趋于稳定,即为完成聚类

    KMeans过程

    KMeans聚类过程

    上图是截取别人blog中的图片(参考文献1),这里讲的其实很清楚了。
    上代码:

    #!/usr/bin/python
    # -*- coding:utf-8 -*-
    """
    Author LiHao
    Time 2018/11/26 9:21
    """
    import os
    import sys
    import numpy as np
    import scipy as sp
    from sklearn.datasets import load_iris
    # 欧式距离函数
    from ml_learn.algorithm.distance import eculide
    import matplotlib.pyplot as plt
    def load_data():
        """
        导入iris标准数据集
        :return:
        """
        iris = load_iris()
        data = iris.data
        target = iris.target
        target_names = iris.target_names
        return data,target,target_names
    
    class Group(object):
        """
        定义类簇的类 -- 后续也会使用
        """
        def __init__(self):
            self._name = ""
            self._no = None
            self._members = []
            self._center = None
        @property
        def no(self):
            return self._no
        @property
        def name(self):
            return self._name
        @name.setter
        def name(self,no):
            self._no = no
            self._name = "G"+str(self._no)
        @property
        def members(self):
            return self._members
        @members.setter
        def members(self,member):
            if member is None:
                raise TypeError("member is None,please set value")
            if isinstance(member,list):
                self.members.extend(member)
                return
            self._members.append(member)
        def clear_members(self):
            self._members = []
        @property
        def center(self):
            return self._center
        @center.setter
        def center(self,c):
            self._center = c
    
    class KMeans(object):
        def __init__(self,k = 2):
            if (k <= 1) or (k is None):
                raise ValueError("k's num must not none and must > 1.")
            self._k = k
            # 类簇
            self._groups = self._make_groups(k)
            self._pre_mean_value = 0
            self._current_mean_value = 1
    
        def _make_groups(self,k):
            """
            生成类簇
            :param k:
            :return:
            """
            groups = []
            for i in range(k):
                g = Group()
                g.name = i+1
                groups.append(g)
            return groups
    
        def _random_x_index(self,xlen):
            indexes = np.random.randint(0,xlen,self._k).tolist()
            return indexes
    
        def _compute_mean_value(self):
            sum = 0
            for i in range(len(self._groups)):
                average = self._compute_members_mean(self._groups[i].members)
                self._groups[i].center = average
                sum += average
            return sum/(len(self._groups))
    
        def _compute_members_mean(self,members):
            np_members = np.array(members)
            average = np.average(np_members,axis=0)
            return average
    
        def _find_most_nearby_group(self,x):
            np_groups = np.array([group.center for group in self._groups])
            distances = eculide(x,np_groups)
            most_similarity_index = np.argmin(distances).squeeze()
            self._groups[most_similarity_index].members = x
            return most_similarity_index
    
        def _clear_groups_members(self):
            for group in self._groups:
                group.clear_members()
    
        def fit(self,X):
            rows,cols = X.shape
            # 1.首先选取k个点为初始聚类中心点
            init_indexes = self._random_x_index(rows)
            for i,index in enumerate(init_indexes):
                self._groups[i].center = X[index]
                self._groups[i].members = X[index]
            # 2.计算每个数据与聚类中心的距离,加入到最近那一个类
            while(True):
                for i in range(rows):
                    #发现距离最近的group 并将数据加入至类簇中
                    self._find_most_nearby_group(X[i])
                # 3.重新计算每个类簇的平均值
                # 计算各个类别的聚类中心并返回所有类簇的均值
                self._current_mean_value = self._compute_mean_value()
                epos = np.sum(self._current_mean_value-self._pre_mean_value,axis=0).squeeze()
                if epos <= 0.00001:
                    break
                # 清除历史成员 并将计算得到的均值误差保存
                self._clear_groups_members()
                self._pre_mean_value = self._current_mean_value
                # 4.重复2-3的运算,直到每个类簇额均值不再发生变化
        def plot_example(self):
            figure = plt.figure()
            ax = figure.add_subplot(111)
            ax.set_title("KMeans Iris Example")
            plt.xlabel("first dim")
            plt.ylabel("third dim")
            legends = []
            cxs = []
            cys = []
            for i in range(len(self._groups)):
                group = self._groups[i]
                members = group.members
                x = [member[0] for member in members]
                y = [member[2] for member in members]
                ax.scatter(x,y,marker='o')
                cx = group.center[0]
                cy = group.center[2]
                cxs.append(cx)
                cys.append(cy)
                legends.append(group.name)
            plt.scatter(cxs, cys, marker='+', c='k')
            plt.legend(legends,loc="best")
            plt.show()
            
    data,target,target_names = load_data()
    kmeans = KMeans(k=3)
    kmeans.fit(data)
    kmeans.plot_example()
    

    经过运行,可以得到类似下图的结果:选取的是iris数据集,展示的是第一维和第三维的二位平面图。iris真实数据是分为3类,每一类50个数据。
    每次运行的结果可能不一样,因为我们选取的初始中心点是随机的,这样就会造成结果的不稳定性。因此,很多K均值的改进方法就会从初始点选取进行优化;还有的是优化了均值计算,变成了中位数计算(K_median算法)


    示例

    参考文献

    1.各种聚类算法(原理+代码+对比分析)最全总结

    相关文章

      网友评论

          本文标题:K均值聚类及代码实现

          本文链接:https://www.haomeiwen.com/subject/tqsdlqtx.html