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>]
