聚类是指将数据集中的样本划分为若干个不相交的子集,子集内元素的相似度大,而子集间元素的相似度小。K-means(K均值)聚类是一种非常简单有效、同时解释性也非常强的算法,看了一些相似内容的博客,将这一内容说的颇为复杂,这里将以尽量简单简介的方式,将这一内容介绍给初学者学习
一、相似度即距离
如开题所说,聚类是通过判断样本间的相似度来进行的,这种相似度我们通常使用样本属性间的距离来衡量,最常用的距离是闵可夫斯距离,定义如下:
其中的p是自定义的参数,当p为2是闵可夫斯基距离即为欧式距离,K-means聚类采用的便是这种距离方案。
二、K-means算法
K-means的核心思想在于,对聚类算法划分得到的k个类别C = {C1,C2,…,Ck}有最小化的平方误差E
其最小化的平房误差求解方案在实际编程时,我们采用循环迭代的方式
1.确定聚类个数k
2.从数据集中随机选取k个样本 ,作为初始均值向量
3.计算数据集中的样本与各个均值向量的距离,划为距离最近的类
4.根据上面的公式计算新的均值向量
5.如果均值向量和之前相比未变则结束聚类,
若不想等则回到第三步重复计算
完整代码地址:https://github.com/LiangjunFeng/Machine-Learning/blob/master/7.K-means.py
模块程序讲解如下:
创建数据
def creatData():
data1 = numpy.mat(numpy.random.randint(0,12,size=(2,50)))
data2 = numpy.mat(numpy.random.randint(8,20,size=(2,50)))
data = numpy.hstack((data1,data2)).T
label1 = numpy.mat(numpy.zeros(50)).T
label2 = numpy.mat(numpy.ones(50)).T
label = numpy.vstack((label1,label2))
return data,label
预备函数
def minkowskiDistance(vector1,vector2,p=2): #闵斯基距离函数
vector1 = numpy.ravel(vector1)
vector2 = numpy.ravel(vector2)
length,distance = len(vector1),0
for i in range(length):
distance += abs(vector1[i] - vector2[i])**p
return distance**(1.0/p)
def randomInt(minimum,maximum): #在给定范围内产生一个整数,用于随机选取初始均值向量
return random.randrange(minimum,maximum,1)
K-mens类
class K_means:
def __init__(self):
self._classes = 0 #聚类类别数
self._averageVectorList = [] #均值向量列表
self._classSetList = [] #样本分类列表
def setUp(self,data,number): #类建立
self._classes = number
self._averageVectorList = [0]*self._classes
for i in range(self._classes):
self._classSetList.append([])
def randomVector(self,data): #随机选择初始均值向量
for i in range(self._classes):
self._averageVectorList[i] = data[randomInt(0,data.shape[0]),:]
def classifiy(self,data): #根据闵斯基距离分类
samples,attributes = data.shape
for i in range(samples):
k = 0
for j in range(self._classes):
if minkowskiDistance(data[i,:],self._averageVectorList[k]) > minkowskiDistance(data[i,:],self._averageVectorList[j]):
k = j
self._classSetList[k].append(i)
def renewAverageVector(self,data): #根据分类数据更新均值向量
for i in range(self._classes):
sum = 0
for j in range(len(self._classSetList[i])):
sum += data[self._classSetList[i][j],:]
self._averageVectorList[i] = numpy.ravel(sum/len(self._classSetList[i]))
def compare(self,vector): #用于比较新旧均值向量是否相等
if vector == []:
return False
for i in range(len(vector)):
if not (self._averageVectorList[i] == vector[i]).all():
return False
return True
def clustering(self,data,number,limits = 100): #聚类函数
self.setUp(data,number)
self.randomVector(data)
oldAverageVector,times = [],0
while (not self.compare(oldAverageVector)) and (times < limits):
oldAverageVector = self._averageVectorList.copy()
self._classSetList.clear()
for i in range(self._classes):
self._classSetList.append([])
self.classifiy(data)
self.renewAverageVector(data)
print(times)
times += 1
测试主函数
if __name__ == '__main__':
data,label = creatData()
C = K_means()
C.clustering(data,2)
for i in range(len(C._classSetList[0])):
p1=plt.scatter(data[C._classSetList[0][i],0],data[C._classSetList[0][i],1],marker='x',color='g')
for i in range(len(C._classSetList[1])):
p2=plt.scatter(data[C._classSetList[1][i],0],data[C._classSetList[1][i],1],marker='+',color='r')
plt.show()
结果:
计算一次
计算三次
计算七次,最终结果
三、更多资源下载
微信搜索“老和山算法指南”获取更多下载链接与技术交流群
有问题可以私信博主,点赞关注的一般都会回复,一起努力,谢谢支持。