赞
踩
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
- }
下面是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)
最后的聚类结果:
1>算法对于符合高斯分布的数据,聚类效果比较好。二维的高斯分布在平面上是一个圆形或者椭圆的形状,如果数据服从这个分布,则用K-Means算法效果比较好。
2>算法对于初值的选择比较敏感,需要多次尝试。可以看到,数据明显分为了三类,但是这是在我们知道算法的类别是3的情况下,如果我们初始化的类别不是3,算法就不会有这么好的效果。特别是对于高维数据,我们无法将数据可视化的情况下,需要多次运行算法,查看算法表现,如果将聚类中心初始化为6,效果就没有那么好了,如下图所示,对于初始点的位置对于算法会有影响,所以提出了改进的K-Means++算法。
3>算法对于异常点比较敏感,比如数据为1,2,3,4,10,100,他们的聚类中心为20,显然这个时候聚类中心离大多数数据比较远,这个时候需要对聚类中心进行改进,选用中位数作为聚类中心,效果会比较好,这就是K-mean的改进算法k-Mediods算法。
将K-Means算法用损失函数表示出来:
上面表示的是每一个样本点到他的聚类中心距离的最小值。直接求解上面的算法是一个NP难的问题,所以一般选择启发式的规则进行。
如果选取要想使得上面的损失函数值变得更小,有两种方法。第一种方法是是保持xi所属的类别不变,更改聚类中心的值。第二种方法。保持聚类中心u不变,改变xi所属的类别。
一开始我们不知道xi对应的最佳聚类中心ui是那一个,所以一开始随便指定一个ui,为了让J最小,我们更新聚类中心ui的值。更新后发现xi有更好的聚类中心uj,这个时候更新xi所属聚类中心为uj。不断重复上述过程。而上述过程对应的是EM算法中的E步和M步,E步就是确定隐含变量类别(即聚类中心),M步就是更新其他参数来最小化J。
参考资料:1>吴恩达机器学习K-means作业
2>机器学习实战
4>CS229机器学习笔记
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。