python实现kmeans图像分割_Python实现K-means聚类算法题记:最近有幸参与了⼀个机器学习的项⽬,我的主要⼯作是帮助进⾏数据预处理,期间⽤Python实现了K-means聚类算法,感觉收获很多特此记录下来和⼤伙⼉分享。
⼀
机器学习项⽬的主要流程
机器学习项⽬的主要流程有五步:
1.数据提取
2.数据清洗
3.特征⼯程
4.训练模型
5.验证模型并优化
之前讲到的PYTHON爬⾍可以算是第⼀步数据提取⾥⾯的内容,数据提取的作⽤就是想⽅设法获取源数
据。获得源数据后,由于源数据⾥可能包含很多的脏数据,⽐如房屋⾯积是零、年龄是负数等等情况,所以需要对源数据进⾏清洗,使数据变得更加整齐有效。然后开始提取数据信息,也就是我们说的特征⼯程。特征⼯程是提升模型强度的关键因素,特征选取的越好,模型效果就越好。然后训练模型,就是出特征x和标签y之间的函数关系式。最后验证这个函数关系式的效果好不好,并进⾏优化。
⼆
聚类算法简介
我这次所做的⼯作就是第⼆步数据清洗。需求是这样的:需要将⼆维坐标系上的点集按距离远近分类,距离近的分成⼀组。以⽅便后续算法⼯程师对各个分组进⾏特征的提取⼯作。
为实现⽬标,常采⽤的就是K-means聚类算法。K-means聚类算法的思路如下:
1.选择分类数K,也就是我们希望把数据分成K组。⼀般根据经验来选取,⽐如⾐服就分成S M L三类,或者根据聚类结果和K的函数式,选择让结果最好的那个K值。
2.随机选择每类数据的中⼼点。中⼼点的选择对结果影响也很⼤,如果选取不好就会到局部最⼩值,这⾥⼀般有两种处理⽅法:⼀是多次取平均值,⼆是采⽤改进算法。
3.计算数据集中所有点到各个中⼼点的距离,它们离哪个中⼼点最近,就把它们划分到哪⼀类⾥⾯去。
4.在每⼀类中通过求平均值的⽅法寻新的中⼼点
5.循环执⾏3、4步,直到分类结果收敛为⽌。(即分类结果不变为⽌)
三
源数据格式
源数据是⼀个存放在e盘下的txt⽂档,其中每⼀⾏数据代表点的横坐标和纵坐标,横坐标和纵坐标之间⽤TAB键分隔,⽂档有多少⾏就代表有多个点。如下:
四
Python代码实现
import numpy
def loadDataSet(fileName):
dataMat = []
fr = open(fileName)
for line adlines():
curLine = line.strip().split('\t') #strip 去除⾸尾的空格,split以tab作为分隔符分割数据。返回⼀个list数据
fltLine =[float(i) for i in curLine]
dataMat.append(fltLine)
return dataMat
# 计算两个向量的距离,⽤的是欧⼏⾥得距离
def distEclud(v1, v2):
return numpy.sqrt(numpy.sum(numpy.square(v1 - v2)))
# 构建聚簇中⼼,取k个(此例中为2)随机质⼼
def randCent(dataSet, k):
n = shape(dataSet)[1] #等价于dataSet.shape[1],得到数组的列数。同理,dataSet.shape[0]得到数组的⾏数。shape函数就是读取矩阵的长度
centroids = mat(zeros((k,n))) # 每个质⼼有n个坐标值,总共要k个质⼼
for j in range(n):
minJ = dataSet[:,j].min() #第j列的最⼩值
maxJ = dataSet[:,j].max() #第j列的最⼤值
rangeJ = maxJ - minJ
return centroids
#def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
def kMeans(dataSet, k):
m = shape(dataSet)[0] #等价于dataSet.shape[0] 第⼀维的长度,即⾏数
clusterAssment = mat(zeros((m, 2))) # ⽤于存放该样本属于哪类及质⼼距离,第⼀列是该数据所属中⼼点,第⼆列是该数据到中⼼点的距离
centroids = randCent(dataSet, k)
clusterChanged = True #判断聚类是否已经收敛,当clusterChanged的值为False时已经收敛,跳出While循环。
while clusterChanged:
clusterChanged = False
for i in range(m): # 每个数据点分配到离它最近的质⼼,range(start,stop,step)⽤于⽣成⼀个整数列表
python新手能做啥兼职minDist = inf #inf代表正⽆穷 -inf代表负⽆穷
minIndex = -1
for j in range(k):
distJI = distEclud(numpy.array(centroids[j, :]), numpy.array(dataSet[i, :])) #求第j⾏的中⼼点到第i⾏的数据之间的距离
if distJI
minDist = distJI;
minIndex = j
if clusterAssment[i, 0] != minIndex:
clusterChanged = True
clusterAssment[i, :] = minIndex, minDist ** 2 # x**y 返回x的y次幂 x//y 取x除以y的整数部分
print(centroids)
for cent in range(k): #重新计算中⼼点
ptsInClust = dataSet[nonzero(clusterAssment[:, 0].A == cent)[0]] # 筛选出第⼀列等于cent的所有数据,即到属于这个聚类的所有数据点。 nonzero函数是numpy中⽤于得到数组array中⾮零元素的位
置(数组索引)的函数
centroids[cent, :] = mean(ptsInClust, axis=0) # mean是求平均值的函数,
# an(a, axis, dtype, out,keepdims ) axis 不设置值,对 m*n 个数求均值,返回⼀个实数
#axis = 0:压缩⾏,对各列求均值,返回 1* n 矩阵 axis =1 :压缩列,对各⾏求均值,返回 m *1 矩阵
return centroids, clusterAssment
def show(dataSet, k, centroids, clusterAssment): #绘图展⽰,这块还没看
from matplotlib import pyplot as plt
numSamples, dim = dataSet.shape
mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '
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', '
for i in range(k): #画中⼼点
plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize=12)
plt.show()
def main():
dataMat =mat(loadDataSet('E:/')) #mat转换成矩阵操作
myCentroids, clustAssing = kMeans(dataMat, 2) #函数返回⼀个元组,元组的括号可以省略
# print(myCentroids)
show(dataMat, 2, myCentroids, clustAssing)
if __name__ == '__main__':
main()
*代码要点精讲*
main()函数:这是程序的起点,它先对⽤loadDataSet函数对源数据做加载,再要⽤kMeans()做聚类,最后⽤show()将聚类结果以图表形式展⽰出来。
loadDataSet()函数:⽤来加载源数据,先⽤open函数打开源⽂件,然后逐⾏读取源⽂件的内容,每⾏内容⽤TAB作为分隔符,每⾏内容形成⼀个列表,附加到dataMat中,最后返回⼀个对象是列表的列表dataMat。⽐如这⾥的txt数据形成⼀个10*2的矩阵给了dataMat。
kMeans()函数:分类结果存放在clusterAssment中,中⼼点存放在centroids中,当标志位clusterChanged为false时,表⽰聚类结束。While循环表⽰每次聚类,⼀次WHILE⾥有双重for循环,表⽰每次聚类时,都要计算所有数据点到中⼼点的距离,数据到哪个中⼼点距离最短,就划分到哪类⾥⾯去。划分完毕后重新计算中⼼点。
Show()函数:⽤于聚类结果的展⽰。导⼊matplotlib库,应⽤其中的plot函数绘图,先绘制样本点再绘制中⼼点。属于同⼀中⼼点的样本点⽤同种标记。
五
聚类结果
从图中我们可以看到⼗个样本点被分成了两类。红⾊的是⼀类,蓝⾊的是⼀类,这个结果符合我们最初的预期。当数据量加⼤的时候,也有同样的效果,这⾥就不赘述了。
六
后记
曾经作为测试⼩⽩的我有很长⼀段时间也认为测试不需要懂代码,特别是功能测试只需要懂业务,然后会跑⽤例就够了。但是当真正遇到⼀些稍微⾼⼤上⼀点的项⽬的时候,才知道测试光懂业务还远远不够,知其然还要知其所以然,才能更好地把控软件产品质量。通过这次"兼职"数据处理⼯程师,在我明⽩这个聚类算法的逻辑后,才能思考怎么测试才能更好了把控产品质量,⽐如说采⽤⼤数据量、采⽤⼀些垃圾数据做⼲扰、采⽤让它收敛到局部最⼩的K值等等。。
测试路上没有最好,只有更好。与各位同仁共勉!
选⾃《51测试天地》第五⼗⼆期电⼦杂志
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论