1.K-Means聚类算法
1.1 K-Means聚类算法基本原理
聚类就是将一大堆数据集中,将具有相同特征的数据自动的归到一类,每一类都称为一个簇。很显然这是一种无监督学习方法。所谓的K-Means(K-均值)算法就是用来发现数据集中K个簇的算法,并且每个簇的中心使用簇中的均值来确定,每个簇的中心叫做质心。
这里的距离一般采用欧式距离来进行计算: 两者欧式距离计算公式为:
1.2 K-Means聚类算法流程简述
算法流程简述:
- 1.随机创建K个点作为初始质心(不一定是数据集中的点)
- 2.分别计算每个数据和质心的欧式距离,并将该数据分类至距离最近的簇,如果簇发生变化则进行记录
- 3.对每一个簇,统计簇中所有的数据点特征的平均值作为新的质心
- 4.弱在上述步骤中不存在簇发生变化的情况发现则算法结束,否则跳转至第2步
1.3 K-Means聚类算法评价标准
K-Means聚类算法一般采用SSE (Sum of Squared Error, 误差平方和 )作为评价标准,也就是每一个点到其所在簇质心的距离的平方的总和。SSE值越小,表明簇内所有点越接近质心,分类效果越好。
1.4 K-Means聚类算法实例
给定的数据集是一个八十行的数据文件,每行两个特征值。现在要求根据这个特征值进行聚类,部分数据集如下:
1.658985 4.285136 -3.453687 3.424321 4.838138 -1.151539 -5.379713 -3.362104 0.972564 2.924086 -3.567919 1.531611 0.450614 -3.302219 -3.487105 -1.724432 2.668759 1.594842
首先从文件中,读入数据,将原始数据转换成np数组
import numpy as np #数据读入函数 def loadData(filename): with open(filename,"r") as f: fileContent = f.read() data = fileContent.split("\n") dataMat = [] for row in data: if row!="": item = row.split("\t") dataMat.append(item) dataMat = np.array(dataMat,dtype="float64") return dataMat dataSet = loadData("attach/1.8/testSet.txt")
各个数据特征分布如下图所示:
#特征分布图 from matplotlib import pyplot as plt for row in dataSet: plt.plot(row[0], row[1], 'o', color='green', markeredgewidth=2, markersize=10) #画点
从图中,我们可以观察出给定数据整体可以分为四个簇,为方便后续计算我们先构建一个计算两个特征向量欧式距离的函数。
import numpy as np def distCalc(vecX,vecY): dist = np.sqrt(np.sum(np.power((vecX-vecY),2)))#神奇的数组计算大大降低了代码量 return dist #print(distCalc(dataSet[0],dataSet[1]))
完成准备工作开始,算法编写,根据算法的基本流程,第一步是要构建k个随机质心
import numpy as np def makeRandCent(dataSet,k): #随机质心创建的时候要注意,质心要在范围空间内 n = dataSet.shape[1] #获取特征数量 centList = np.zeros((k,n)) for i in range(n): minI = np.min(dataSet[:,i]) rangeI = np.max(dataSet[:,i])-minI centList[:,i] = minI + rangeI*np.random.rand(1,k) return centList centList = makeRandCent(dataSet,4) #生成随机的质心
print(centList)
[[ 0.65663247 0.77717004] [-0.84559261 -0.73683408] [-0.61538579 0.69684389] [ 0.70073271 -0.68287865]]
def kMeans(dataSet,k): typeChange = True numOfdata = dataSet.shape[0] dataClassifyRes = [-1]*80 while typeChange: typeChange = False indexOfData = 0 for data in dataSet: num=0 minDist = np.inf minIndex = -1 for cent in centList: dist = distCalc(data,cent) if dist<minDist: minDist = dist minIndex = num num+=1 if minIndex==dataClassifyRes[indexOfData]: pass else: dataClassifyRes[indexOfData]=minIndex #print(indexOfData,"------》",minIndex) typeChange = True indexOfData+=1 #更新k个质心的特征值 for i in range(k): indexListOfThisType = [] for index,value in enumerate(dataClassifyRes): if value==i: indexListOfThisType.append(index) for j in range(centList.shape[1]): SUM = 0.0 for index in indexListOfThisType: SUM += dataSet[index][j] centList[i][j] = (SUM/(len(indexListOfThisType))) return dataClassifyRes res = kMeans(dataSet,4)
from matplotlib import pyplot as plt for index,value in enumerate(res): if value==0: plt.plot(dataSet[index][0], dataSet[index][1], 'x', color='green', markeredgewidth=2, markersize=10) #画点 if value==1: plt.plot(dataSet[index][0], dataSet[index][1], 'x', color='red', markeredgewidth=2, markersize=10) #画点 if value==2: plt.plot(dataSet[index][0], dataSet[index][1], 'x', color='blue', markeredgewidth=2, markersize=10) #画点 if value==3: plt.plot(dataSet[index][0], dataSet[index][1], 'x', color='orange', markeredgewidth=2, markersize=10) #画点 #画出四个质心点 plt.plot(centList[0][0], centList[0][1], 'o', color='green', markeredgewidth=2, markersize=10) #画点 plt.plot(centList[1][0], centList[1][1], 'o', color='red', markeredgewidth=2, markersize=10) #画点 plt.plot(centList[2][0], centList[2][1], 'o', color='blue', markeredgewidth=2, markersize=10) #画点 plt.plot(centList[3][0], centList[3][1], 'o', color='orange', markeredgewidth=2, markersize=10) #画点
[<matplotlib.lines.Line2D at 0x119bc2e10>]