《机器学习实战》之二分K-均值聚类算法的python实现
来源:互联网 发布:阿里云为什么要幕布 编辑:程序博客网 时间:2024/05/20 06:56
《机器学习实战》之二分K-均值聚类算法的python实现
上面博文介绍了K-均值聚类算法及其用python实现,上篇博文中的两张截图,我们可以看到,由于K-均值聚类算法中由于初始质心的选取,会造成聚类的局部最优,并不是全局最优,因此,会造成聚类的效果并不理想,为克服K-均值算法收敛于局部最小值的问题,就有了二分K-均值算法。
二分K-均值聚类算法
二分K均值算法是基本K均值算法的直接扩充,其基本思想是:为了得到K个簇,首先将所有点的集合分裂成两个簇,然后从这些簇中选取一个继续分裂,迭代直到产生K个簇;二分K均值的关键是如何选择待分裂簇,选择策略主要有两种,一是选择包含矢量个数最多的簇进行分裂,二是选择具有最大SSE(误差的平方和)的簇分裂。
二分k均值算法的伪代码如下:
将所有数据点看成一个簇
当簇数目小于k时
对每一个簇
计算总误差
在给定的簇上面进行k-均值聚类(k=2)
计算将该簇一分为二后的总误差
选择使得误差最小的那个簇进行划分操作
另一种做法是选择SSE最大的簇进行划分,直到簇数目达到用户指定的数目为止。
python实现如下
环境:python 3.4 使用的库:numpy、matplotlib
biKmeans.py:此文件中的kmeans算法与上篇博文中的代码一致,在上一篇博文中注释写的比较详细,这里就没有在详细注释,若需要看注释,可以看上一篇博文
# 二分k均值算法的伪代码如下:#***************************************************************#将所有数据点看成一个簇##当簇数目小于k时## 对每一个簇## 计算总误差## 在给定的簇上面进行k-均值聚类(k=2)## 计算将该簇一分为二后的总误差## 选择使得误差最小的那个簇进行划分操作##*************************************************************** from numpy import * import time import matplotlib.pyplot as plt # calculate Euclidean distance def euclDistance(vector1, vector2): return sqrt(sum(power(vector2 - vector1, 2))) # init centroids with random samples def initCentroids(dataSet, k): numSamples, dim = dataSet.shape centroids = zeros((k, dim)) for i in range(k): index = int(random.uniform(0, numSamples)) print(index) centroids[i, :] = dataSet[index, :] return centroids # k-means cluster def kmeans(dataSet, k): numSamples = dataSet.shape[0] # first column stores which cluster this sample belongs to, # second column stores the error between this sample and its centroid clusterAssment = mat(zeros((numSamples, 2))) clusterChanged = True ## step 1: init centroids centroids = initCentroids(dataSet, k) while clusterChanged: clusterChanged = False ## for each sample for i in range(numSamples): minDist = 100000.0 minIndex = 0 ## for each centroid ## step 2: find the centroid who is closest for j in range(k): distance = euclDistance(centroids[j, :], dataSet[i, :]) if distance < minDist: minDist = distance minIndex = j ## step 3: update its cluster if clusterAssment[i, 0] != minIndex: clusterChanged = True clusterAssment[i, :] = minIndex, minDist**2 ## step 4: update centroids for j in range(k): pointsInCluster = dataSet[nonzero(clusterAssment[:, 0].A == j)[0]] centroids[j, :] = mean(pointsInCluster, axis = 0) print ('Congratulations, cluster using k-means complete!' ) return centroids, clusterAssment # bisecting k-means cluster def biKmeans(dataSet, k): numSamples = dataSet.shape[0] # first column stores which cluster this sample belongs to, # second column stores the error between this sample and its centroid clusterAssment = mat(zeros((numSamples, 2))) # step 1: the init cluster is the whole data set #mean(dataSet,axis=0)返回的是:matrix([[XXX,XXX,XXX]]) #mean(dataSet, axis = 0).tolist()返回的是:[[XXX,XXX,XXX]], #mean(dataSet, axis = 0).tolist()[0],返回的是:[XXX,XXX,XXX] centroid0 = mean(dataSet, axis = 0).tolist()[0] #列表中的第一个列表元素:即全部数据每个属性对应的均值 centList = [centroid0] #centList是[[xxx,xxx,xxx]] for j in range(numSamples): clusterAssment[j, 1] = (euclDistance(mat(centroid0), dataSet[j, :]))**2 #计算每个样本点与质心之间的距离 while (len(centList) < k): # min sum of square error minSSE = inf #numCurrCluster = len(centList) #当前的簇的个数 # for each cluster #找出numCurrCluster个簇中哪个簇分解得到的误差平方和最小的两个簇 for i in range(len(centList)): # step 2: get samples in cluster i #选取第i个簇的所有数据,然后将其分成两个两个簇 pointsInCurrCluster = dataSet[nonzero(clusterAssment[:, 0].A == i)[0], :] # step 3: cluster it to 2 sub-clusters using k-means #centroids的元素为每个簇的质心 #splitClusterAssment第一列为样本所属的类别号,第二列为样本到其所属簇的质心的距离的平方 #每个2均值聚类时循环N次,去除kmeans的初始值随机选取不当 N=20 minSSE_kmeans=100000.0; for j in range(N): centroids_kmeans, splitClusterAssment_kmeans = kmeans(pointsInCurrCluster, 2) if (sum(splitClusterAssment_kmeans[:, 1]))<minSSE_kmeans: minSSE_kmeans=sum(splitClusterAssment_kmeans[:, 1]) splitClusterAssment=splitClusterAssment_kmeans centroids=centroids_kmeans # step 4: calculate the sum of square error after split this cluster #下面的代码是求误差平方和 #splitSSE=sum(power(splitClusterAssment[:,1],2)) splitSSE = sum(splitClusterAssment[:, 1]) #不是标号为第i个簇的误差平方和 notSplitSSE = sum(clusterAssment[nonzero(clusterAssment[:, 0].A!=i)[0], 1]) currSplitSSE = splitSSE + notSplitSSE #当前所有簇的平方和 print('num=%d,%s,%s,%s' %(i,splitSSE,notSplitSSE,currSplitSSE)) # step 5: find the best split cluster which has the min sum of square error if currSplitSSE < minSSE: # bestCentroidToSplit = i bestNewCentroids = centroids bestClusterAssment = splitClusterAssment.copy() minSSE = currSplitSSE print('minSSE=%s' %minSSE) # step 6: modify the cluster index for adding new cluster #将新分出来的两个簇的标号一个沿用它父亲的标号,一个用簇的总数来标号。 bestClusterAssment[nonzero(bestClusterAssment[:, 0].A == 1)[0], 0] = len(centList) bestClusterAssment[nonzero(bestClusterAssment[:, 0].A == 0)[0], 0] = bestCentroidToSplit # step 7: update and append the centroids of the new 2 sub-cluster centList[bestCentroidToSplit] = bestNewCentroids[0, :] #将第一个子簇的质心放在父亲质心的原位置 centList.append(bestNewCentroids[1, :]) #将第二个子簇的质心添加在末尾 # step 8: update the index and error of the samples whose cluster have been changed #由第i个簇分解为j、k两个簇所得到的数据将分解之前的数据替换掉 clusterAssment[nonzero(clusterAssment[:, 0].A == bestCentroidToSplit)[0], :] = bestClusterAssment print ('Congratulations, cluster using bi-kmeans complete!' ) return mat(centList), clusterAssment # show your cluster only available with 2-D data def showCluster(dataSet, k, centroids, clusterAssment): numSamples, dim = dataSet.shape if dim != 2: print ("Sorry! I can not draw because the dimension of your data is not 2!" ) return 1 mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr'] if k > len(mark): print ("Sorry! Your k is too large!") return 1 # draw all samples for i in range(numSamples): markIndex = int(clusterAssment[i, 0]) plt.plot(dataSet[i, 0], dataSet[i, 1], mark[markIndex]) mark = ['Dr', 'Db', 'Dg', 'Dk', '^b', '+b', 'sb', 'db', '<b', 'pb'] # draw the centroids for i in range(k): plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize = 12) plt.show()
测试文件test.py:与K均值聚类这篇博文中的代码相同,这里也就没有再注释
################################################# # kmeans: k-means cluster # Author :wojiushimogui # Date :2015年7月28日11:12:44# HomePage :http://write.blog.csdn.net/postlist# Email : ################################################# from numpy import * import time import matplotlib.pyplot as plt import biKMeansfrom biKMeans import *## step 1: load data print ("step 1: load data..." ) dataSet = [] fileIn = open('D:/xuepython/BiKmeans/testSet.txt') for line in fileIn.readlines(): lineArr = line.strip().split('\t') dataSet.append([float(lineArr[0]), float(lineArr[1])]) ## step 2: clustering... print ("step 2: clustering...") dataSet = mat(dataSet) k = 4 centroids, clusterAssment = biKmeans(dataSet, k) ## step 3: show the result print ("step 3: show the result..." )showCluster(dataSet, k, centroids, clusterAssment)
运行结果截图如下:
是乃遗憾,运行的结果也不是我们想象的那样,聚类的结果也是随机的,不是那么的理想,但是,按照《机器学习实战》这本书上面提供的二分K-均值聚类算法的思想:找到分解使得总的SSE最小(即找到那个簇使得分解后能够最大的降低SSE))来看,应该是不会出现上面的问题的,但是今天无论是我参考《机器学习实战》这本书上面的源代码,还是这篇博客中的源码,都不能解决这个问题。
由于在参考《数据挖掘导论》这本书上面的二分K均值聚类时看到如下的伪代码。
初始化簇表,使之包含由所有点组成的簇repeat 从簇表中取出一个簇 {对选定的簇进行多次二分“实验”} for i= 1 to 实验次数 do 使用基本K均值,二分选定的簇。 end for 从二分试验中选择具有最小总SSE的两个簇 将这两个簇添加到簇表中。until 簇表中包含K个簇
因此,按照上面的思路,我在《机器学习实战》上面的源码中添加了如下代码。
#每个2均值聚类时循环N次,去除kmeans的初始值随机选取不当 N=20 minSSE_kmeans=100000.0; for j in range(N): centroids_kmeans, splitClusterAssment_kmeans = kmeans(pointsInCurrCluster, 2) if (sum(splitClusterAssment_kmeans[:, 1]))<minSSE_kmeans: minSSE_kmeans=sum(splitClusterAssment_kmeans[:, 1]) splitClusterAssment=splitClusterAssment_kmeans centroids=centroids_kmeans
发现,依然还是没有办法解决这个问题。
马上就要去跑步了,今天就思考到这里,明天我将会换一种方法来解决这个问题:通过找到最大的SSE的那个簇,然后将其分解;按照这样一个思路我相信应该可以解决这个问题。
源码和测试数据在这里可以获取
身体是自己的,科研是老板的,哈哈
跑步去了
- 《机器学习实战》之二分K-均值聚类算法的python实现
- 《机器学习实战》之K-均值聚类算法的python实现
- 机器学习实战:K-均值及二分K-均值聚类算法
- 机器学习经典算法详解及Python实现--聚类及K均值、二分K-均值聚类算法
- 机器学习经典算法详解及Python实现--聚类及K均值、二分K-均值聚类算法
- 【机器学习实战之三】:C++实现K-均值(K-Means)聚类算法
- 机器学习算法与Python实践之(六)二分k均值聚类
- 机器学习算法与Python实践之(六)二分k均值聚类
- 机器学习算法与Python实践之(六)二分k均值聚类
- 机器学习算法与Python实践之(六)二分k均值聚类
- 机器学习算法与Python实践之(六)二分k均值聚类
- 《机器学习实战》二分-kMeans算法(二分K均值聚类)
- 机器学习实战之 第10章 K-Means(K-均值)聚类算法
- PYTHON机器学习实战——K均值聚类
- 【机器学习实战04】k-均值聚类算法
- 《机器学习实战》第十章 :K-均值聚类算法
- 【机器学习实战-python3】K-均值聚类算法
- 机器学习算法与Python实践之(五)k均值聚类(k-means)
- 【Leetcode】Lowest common treenode in binary tree
- Fence Repair(POJ--3253
- Linux交叉编译工具
- 黑马程序员——高新技术---Java基础-IO流
- Oracle学习笔记+作业
- 《机器学习实战》之二分K-均值聚类算法的python实现
- nyoj 55 懒省事的小明
- C/C++中的static关键字
- HDU 5289 - Assignment(multiset + 尺取法)
- Elman神经网络的实例(预测结果,函数回归)
- mac修改账户密码
- cookie_session
- 53. Maximum Subarray
- 欢迎使用CSDN-markdown编辑器