写在前面
对机器学习一直很有兴趣,这段时间一直在看这方面的资料,今天记录下自己对K-means算法的学习,主要是研究了下zouxy09大神的文章。文章中有不足不妥的地方欢迎提醒交流,多谢!
正式开始
关于k-means的理论知识,可以参考9神的文章,当然谷歌百度上也有很多。推荐都看看,集多家之所长,会让自己收获的更多。我这里就不再赘述了【懒癌一个】
执行流程
确定分类簇数k,可通过查看散点分布
随机选取质心点矩阵
对数据集中每个点进行迭代,计算每个点与各质心点的距离,选取距离数据点最近的质心点簇作为自己的类簇
直到数据集中所有数据点的类别不变为止
可视化分类点
执行结果
数据集是引用9神文章中的测试数据
开始读取数据
绘制散点图
可以看出图片中的散点分布大致成4或则5类,这里我设置的类簇数为4。
以下是执行分类计算的代码执行结果
调用开始进行数据聚类
开始质心选取
初始化质点点完成[[-1.786345 2.554248]
[ 3.367037 -3.184789]
[ 2.884105 3.043438]
[-3.284816 3.273099]]
开始分类
第1轮更新质点完成[[-2.93239418 -0.59719121]
[ 2.21588922 -2.88365904]
[ 2.6265299 3.10868015]
[-3.29756333 2.80177833]]
第2轮更新质点完成
[[-3.4967025 -2.70989515]
[ 2.65077367 -2.79019029]
[ 2.6265299 3.10868015]
[-2.45009747 2.89275747]]
第3轮更新质点完成
[[-3.53973889 -2.89384326]
[ 2.65077367 -2.79019029]
[ 2.6265299 3.10868015]
[-2.46154315 2.78737555]]
第4轮更新质点完成
[[-3.53973889 -2.89384326]
[ 2.65077367 -2.79019029]
[ 2.6265299 3.10868015]
[-2.46154315 2.78737555]]
已完成数据分类
开始绘图
总共迭代了四轮,其实可以看出第四轮迭代后的质心矩阵与第三轮的质心矩阵一致,也就是实际上迭代了3轮,就已经分好类。看着结果还不错。
分类代码
以下是参考zouxy09大神的代码,我这里做了一些改动
# -*- coding:utf-8 -*-
from numpy import *
import matplotlib.pyplot as plt
class Kmeans():
def __init__(self,dataSet,k):
self.dataSet = dataSet
self.k = k #质点数
self.numSamples = dataSet.shape[0] #矩阵的行数
self.dim = dataSet.shape[1] #矩阵的列数
self.signData = mat(zeros((self.numSamples,2))) #标签矩阵
#计算欧氏距离
def euclDistance(self,vector1,vector2):
return sqrt(sum(power(vector1 - vector2 ,2)))
def dataCount(self):
print u"开始质心选取"
# centroids = zeros((self.k,self.dim))
tem = [int(random.uniform(0,self.numSamples)) for i in xrange(self.k)]
centroids = self.dataSet[tem]
print u'初始化质点点完成\n'
print centroids
clusterChanged = True
print u"开始分类"
count = 0
while clusterChanged:
clusterChanged = False
for i in xrange(self.numSamples):
minDist = 1000000000
index = 0
for j in xrange(self.k):
distance = self.euclDistance(centroids[j,:],self.dataSet[i,:])
if distance < minDist:
minDist = distance
index = j
#检查标签
if self.signData[i,0] != index:
clusterChanged = True
self.signData[i,:] = index,minDist**2
#更新质点
for i in range(self.k):
pointsInCluster = self.dataSet[nonzero(self.signData[:,0].A==i)[0]]
centroids[i,:] = mean(pointsInCluster,axis=0)
count +=1
print u"第{}轮更新质点完成\n".format(count)
print centroids
print '*'*200 #分隔
print u"已完成数据分类"
print u'开始绘图'
if self.dim !=2:
print u"无法绘制2纬图"
return 1
mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr'] #设置绘图颜色
if k > len(mark):
print u"选择的类别数太大,请重新确认类别数"
return 1
for i in xrange(self.numSamples):
markIndex = int(self.signData[i,0])
plt.plot(self.dataSet[i,0],self.dataSet[i,1],mark[markIndex]) #绘制分类图形
mark = ['Dr', 'Db', 'Dg', 'Dk', '^b', '+b', 'sb', 'db', '<b', 'pb'] #设置质心绘图颜色
for i in range(self.k):
plt.plot(centroids[i,0],centroids[i,1],mark[i],markersize=12)
plt.show()
if __name__=='__main__':
print u'开始读取数据'
dataSet = []
with open('D:/datajl.txt') as files:
for line in files.readlines():
line = line.strip().split(',')
# print line,type(line)
dataSet.append([float(line[0]),float(line[1])])
dataSet = mat(dataSet)
print u'绘制散点图'
for x in xrange(dataSet.shape[0]):
plt.plot(dataSet[x,0],dataSet[x,1],'ob')
plt.show()
k = 4
print u'开始进行数据聚类'
Kmeans = Kmeans(dataSet,k)
Kmeans.dataCount()
遇到的问题
- 迭代计算中的时候总是报错,一轮都迭代不下去,核实了下代码,发现自己将记录标签的矩阵和质心矩阵弄混了,修改后,结果就能刷的一下出来了。
最后
任何算法都有其弊端,关于kmeans的缺点,还是参考zouxy09的文章吧,我就不误导了。
衷心感谢所有在互联网上分享自己技术文章的前辈们!
参考
- 机器学习算法与Python实践之(五)k均值聚类(k-means)
http://blog.csdn.net/zouxy09/article/details/17589329
最后希望对看到此处的你有所帮助【微笑】