K均值算法是学习无监督学习的第一个算法,这个算法理解和实现都比较简单,算法的目的是将数据分成K组。
为了达到这个目的,算法首先随机初始化k个数据点(聚类中心),然后遍历所有数据,计算出每一个数据到k个点的距离,找到最小的距离,则该点属于这个类。之后计算每一组中的平均值,然后更新聚类中心,直到中心点不再发生变化。
下面是算法的流程图:
下面是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)
最后的聚类结果:
可以看到,算法几乎将数据准确的分成了三类,但是这是在我们知道算法的类别是3的情况下,如果我们初始化的类别不是3,算法就不会有这么好的效果。特别是对于高维数据,我们无法将数据可视化的情况下,需要多次运行算法,查看分类效果。将聚类中心初始化为6,效果就没有那么好了,如下图所示:
参考资料:1>吴恩达机器学习K-means作业
2>机器学习实战