k-Means算法(Machine Learning in Action)基于python3.6
K-均值算法首先随机确定k个初始点作为质心,为每个点找距其最近的质心,并将分配给质心所对应的簇,然后每个簇的质心更新为该簇所有点的平均值。
优点:容易实现
缺点:可能收敛到局部最小值,在大规模数据集上收敛较慢
适用数据类型:数值型数据
1 ''' 2 创建k个点作为起始质心(经常是随机选择) 3 当任意一个点的簇分配结果发生改变时 4 对数据集中的每个数据点 5 对每个质心 6 计算质心与数据点之间的距离 7 将数据点分配到距其最近的簇 8 对每一个簇,计算簇中所有点的均值并将均值作为质心 9 ''' 10 from numpy import * 11 #读取文本文件到一个列表中 12 def loadDataSet(filename): 13 dataMat=[] 14 fr = open(filename) 15 for line in fr.readlines(): 16 curline = line.strip().split('\t') 17 fltline = list(map(float,curline)) 18 dataMat.append(fltline) 19 return dataMat 20 21 #求欧式距离 22 def distEclud(vecA, vecB): 23 return sqrt(sum(power(vecA - vecB, 2))) 24 25 #构建簇质心 26 def randCent(dataSet, k): 27 n = shape(dataSet)[1]#列表列数 28 centroids = mat(zeros((k,n))) 29 for j in range(n): 30 minJ = min(dataSet[:,j])#第j列的最小值 31 maxJ = max(dataSet[:,j])#第j列的最大值 32 rangeJ = float(maxJ - minJ)#第j列的变化范围 33 centroids[:,j] = mat(minJ + rangeJ * random.rand(k,1))#生成在边界内的随机数 34 return centroids 35 36 datMat = mat(loadDataSet('testSet.txt')) 37 ''' test---------------------------------------- 38 print(min(datMat[:,0])) 39 print(min(datMat[:,1])) 40 print(max(datMat[:,0])) 41 print(max(datMat[:,1])) 42 print(randCent(datMat, 2)) 43 print(distEclud(datMat[0], datMat[1])) 44 45 ''' 46 ''' 47 core code: 48 计算质心-分配-重新计算 49 ''' 50 #分别是数据集,聚类类数,距离函数,创建初始质心函数) 51 def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent): 52 m = shape(dataSet)[0]#行数 53 result = mat(zeros((m,2)))#结果矩阵,一列记录簇索引值,一列记录存储误差(当前点到簇质心的距离) 54 centroids = createCent(dataSet, k)#簇质心 55 changed = True#标志变量,如果为True,继续迭代,若任一点簇分配结果发生变化,更新changed 56 while changed: 57 changed = False 58 for i in range(m): 59 minDist = inf#正负无穷 60 minIndex = -1 61 #寻找最近的质心 62 for j in range(k): 63 distJI = distMeas(centroids[j,:],dataSet[i,:])#算点到每一个质心的距离 64 if distJI < minDist: 65 minDist = distJI; minIndex = j 66 if result[i,0] != minIndex: changed = True#如果更新后的结果矩阵簇索引值与原来的不同,标志位置为True 67 result[i,:] = minIndex,minDist ** 2#结果矩阵此时这一行第一列为点到质心距离最小的那一个质心,第二列为距离的平方 68 #更新质心的位置 69 print(centroids) 70 for cent in range(k): 71 ptsInClust = dataSet[nonzero(result[:,0].A == cent)[0]]#.A变成数组,获取给定簇的所有点 72 centroids[cent,:] = mean(ptsInClust, axis = 0)#按列方向求均值 73 return centroids, result 74 75 # test------------------------------------------------ 76 myCentroids, result = kMeans(datMat,4) 77 print(myCentroids) 78 print('\n') 79 print(result)