K均值算法【K-means】

一、K-Means算法流程

K均值算法是学习无监督学习的第一个算法,这个算法理解和实现都比较简单,算法的目的是将数据分成K组。

为了达到这个目的,算法首先随机初始化k个数据点(聚类中心),然后遍历所有数据,计算出每一个数据到k个点的距离,找到最小的距离,则该点属于这个类。之后计算每一组中的平均值,然后更新聚类中心,直到中心点不再发生变化。

下面是算法的运行过程:

输入:没有标签的数据X,大小为m,要将数据划分成k组。
  u1,u2,u3,...,uk为聚类中心
  x1,x2,...,xm为m个数据
  
  初始化聚类中心u1,u2,...,uk
   Repeat{
      for i=1 到m:
          for j=1 到k:
             计算xi到uj之间的距离,找到最小的距离
             将数据xi划分到产生最小距离的uj组里面
      for i=1到k:
          计算每一组的均值,更新u1,u2,...,uk
   }

 

二、K-Means算法python实现

下面是python的代码实现:

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import scipy.io as sio
import numpy as np

#读入数据,将数据转化为DataFrame
mat = sio.loadmat('ex7data2.mat')
data = pd.DataFrame(mat.get('X'),columns=['X1','X2'])

# 将数据可视化
sns.set(context='notebook',style='white')
sns.lmplot('X1','X2',data=data,fit_reg=False)

数据如下图所示:

#计算两个向量之间的距离
def distEclud(vecA,vecB):
    return np.sqrt(np.sum(np.power(vecA-vecB,2)))

#随机选择K个聚类中心,进行初始化化
def randCent(dataSet,k):
    # n是数据的维数
    n = np.shape(dataSet)[1]
    centroids = np.mat(np.zeros((k,n)))
    for j in range(n):
        minJ = min(dataSet[:,j])
        rangeJ = float(max(dataSet[:,j])-minJ)
        centroids[:,j] = minJ + rangeJ*np.random.rand(k,1)
    return centroids

def KMeans(dataSet,k,distMeans=distEclud,createCent=randCent):
    m = np.shape(dataSet)[0]
    clusterAssment = np.zeros((m,2))
    centroids = createCent(dataSet,k)
    clusterChanged = True
    while clusterChanged:
        clusterChanged = False
        # 遍历所有样本
        for i in range(m):
            minDist = np.inf
            minIndex = -1
            # 对于一个样本,计算他和每一个聚类中心的距离,找到最小的距离
            for j in range(k):
                distJI = distMeans(centroids[j,:],dataSet[i,:])
                if distJI < minDist:
                    minDist = distJI
                    minIndex = j
            if clusterAssment[i,0] != minIndex:
                clusterChanged=True
            clusterAssment[i,:] = minIndex,minDist**2
        print(centroids)
        #求每一个组的均值,更新聚类中心
        for cent in range(k):
            ptsInClust = dataSet[np.nonzero(clusterAssment[:,0]==cent)[0]]
            centroids[cent,:] = np.mean(ptsInClust,axis=0)
    return centroids,clusterAssment
#调用函数,进行聚类
myCentroids,clustAssing =KMeans(data.values,3)

#将类别添加到数据中
data['C'] = clustAssing[:,0]

#绘制分类后的数据
sns.lmplot('X1','X2',hue='C',data=data,fit_reg=False)

最后的聚类结果:

 

 

三、K-Means算法的优缺点及适用范围

1>算法对于符合高斯分布的数据,聚类效果比较好。二维的高斯分布在平面上是一个圆形或者椭圆的形状,如果数据服从这个分布,则用K-Means算法效果比较好。

2>算法对于初值的选择比较敏感,需要多次尝试。可以看到,数据明显分为了三类,但是这是在我们知道算法的类别是3的情况下,如果我们初始化的类别不是3,算法就不会有这么好的效果。特别是对于高维数据,我们无法将数据可视化的情况下,需要多次运行算法,查看算法表现,如果将聚类中心初始化为6,效果就没有那么好了,如下图所示,对于初始点的位置对于算法会有影响,所以提出了改进的K-Means++算法。

3>算法对于异常点比较敏感,比如数据为1,2,3,4,10,100,他们的聚类中心为20,显然这个时候聚类中心离大多数数据比较远,这个时候需要对聚类中心进行改进,选用中位数作为聚类中心,效果会比较好,这就是K-mean的改进算法k-Mediods算法。

四、K-Means算法中的EM思想

将K-Means算法用损失函数表示出来:

                                                J(c,u)=\sum_{i=1}^{m}||x_{i}-u_{ci}||^{2}

上面表示的是每一个样本点到他的聚类中心距离的最小值。直接求解上面的算法是一个NP难的问题,所以一般选择启发式的规则进行。

如果选取要想使得上面的损失函数值变得更小,有两种方法。第一种方法是是保持xi所属的类别不变,更改聚类中心的值。第二种方法。保持聚类中心u不变,改变xi所属的类别。

一开始我们不知道xi对应的最佳聚类中心ui是那一个,所以一开始随便指定一个ui,为了让J最小,我们更新聚类中心ui的值。更新后发现xi有更好的聚类中心uj,这个时候更新xi所属聚类中心为uj。不断重复上述过程。而上述过程对应的是EM算法中的E步和M步,E步就是确定隐含变量类别(即聚类中心),M步就是更新其他参数来最小化J。

 

参考资料:1>吴恩达机器学习K-means作业

        2>机器学习实战

        3>pluskid聚类博客

        4>CS229机器学习笔记

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值