k-means Clustering即K均值聚类算法是一类运用广泛的聚类算法。
聚类
聚类是指把对象划分为多个组或者“聚簇”,从而使得同组对象之间比较相似,而不同组对象之间差异较大。
因为聚类过程中,并没有输入和待聚类对象之间的联系信息,因此聚类通常被看做无监督学习。
k-means算法是一种简单的聚类算法,主要通过迭代来将数据集分类。
算法的输入对象可以看做是 d 维向量空间的一些点,即对集合 D={xi|i=1,2,3,...,n} 进行聚类,并且其中 xi∈Rd 表示第i个数据点。而k-means聚类则是对D中的所有数据点进行处理,聚类中心可以表示为 C={Ki|i=1,2,...,k} ,并且将每个数据点可以记为 xi∈S(Kj) 即表示对第 i 个数据点属于聚类中心 Kj 。
对于聚类算法,通常需要定义一种依据来判断每个数据点属于哪个聚类中心,而这个依据通常被称为代价函数。在一般情况下,我们选取的聚类函数通常如下:
输入:数据集 D ,聚类数 k
输出:聚类集合 C ,聚簇成员向量 m⃗
至于算法中怎么找到初始的聚类中心,怎么计算,度量函数的选择,在后面都会提到。
相关辅助函数
from numpy import *
def loadDataSet(filename) :
dataMat = []
fr = open(filename) :
for line in fr.readlines() :
curLine = line.strip().split('\t')
fltLine = map(float, curLine)
dataMat.append(fltLine)
return dataMat
#Eclud Distance
def distEclud(vecA, vecB):
return sqrt(sum(power(vecA - vecB, 2)))
#Initial Random Clustering Centroids
def randCent(dataSet, k):
n = shape(dataSet)[1]
centroids = mat(zeros((k,n)))
for j in range(n):
minJ = min(dataSet[:,j])
rangeJ = float(max(dataSet[:,J]) - minJ)
centroids[:,J] = minJ + rangeJ * random.rand(k,1)
return centroids
这个是两个辅助的函数,第一个函数定义了我们之前说的常用的一个度量——欧几里得距离,简称欧式距离。第二个辅助函数是用来随机初始化聚类中心的函数,其中centroids是聚类中心,dataSet是数据集合,k是聚类中心的数量,其中随机化的方法是找到数据的最小值和最大值,再在这两个数之间产生k个随机的值。
K-means算法
def kMeans(dataSet, k, distMeas = distEclud, createCent = randCent) :
m = shape(dataSet)[0]
clusterAssment = mat(zeros((m,2)))
centroids = createCent(dataSet, k)
clusterChanged = True
while clusterChanged:
clusterChanged = False
for i in range(m) :
minDist = inf
minIndex = -1
for j in range(k) :
distJI = distMeas(centroids[j,:],dataSet[i,:])
if distJI < minDist :
minDist = distJI
minIndex = j
if clusterAssment[i,0] != minIndex:
clusterChanged = True
clusterAssment[i,:] = minIndex, minDist**2
for cent in range(k) :
ptsInClust = dataSet[nonzero(clusterAssment[:,0].A == cent)[0]]
centroids[cent,:] = mean(ptsInClust, axis = 0)
return centroids, clusterAssment
在这一部分算法中,按照上面的说明,总共包含了三部分内容,即初始化聚类中心,寻找对于每个目标点最近的聚类中心,更新聚类中心的位置,当且仅当聚类中心收敛时,停止算法。我个人认为这里应当简单的加上停止算法,当迭代一定的次数时。
算法初始化了一个m行,2列的一个矩阵clusterAssment,这个矩阵的每一行都对应了一个目标点,而每一行的第一个位置记录了聚类中心,第二个位置记录了这个目标点到聚类中心的距离的平方。在判断聚类中心是否改变时,程序的判断依据是新的距离和clusterAssment里面储存的距离的对比。
程序的最后一部分内容是通过计算每个聚类中心所对应的目标点的值得均值, 来重新计算聚类中心。
k-means算法在本质上属于非凸函数的贪婪下降求解算法, 因此在理论上,最后得到的收敛解都只是局部最优解而并非是全局最优解。并且是否最终能够取到全局最优解在一定程度上与初始的聚类中心的位置也是相关的,对相同的数据集,如果一开始选取的聚类中心不同,那么最终聚类出的结果可能不相同。
所以在解决这个问题上,主要是通过合理的选择初始化的聚类中心以及在算法上做优化防止出现局部最优解。
在实际中,由于对数据集的分布情况缺乏先验的了解,因此有可能并不能预先知道