首页 > 代码库 > k-Means 算法分析
k-Means 算法分析
本人小白,第一次发布博客,大神绕路,不喜勿喷。
最近公司要求一些机器学习的内容,所以在看一些机器学习有关的资料,最近看的书名字叫做 机器学习实战。这是一本不错的书籍,很值得一读。
好,不说废话,进入我们今天的正题。
k-均值算法(k-means算法)
1.k-means算法是一种聚类算法。
何为聚类?聚类就是你在分类之前并不知道有几类,也不知道分别是哪几类,而让计算机根据数据的特征分成不同的几个类别,这些类别没有进行事先定义。这种分类方法又被称为无监督分类。
2.算法思想
在数据集中随机选取k个初始点作为质心,将数据集中的每一个点分配到一个簇中,为每个点找距离其最近的质心,将其分配到该质心所对应的簇,这一步完成之后,每个簇的质心更新为该簇所有点的平均值。到这里初始质心已经发生变化,重复以上步骤n次直到之心不再发生变化为止。
3.Python实现
# coding=utf-8
from numpy import *
import matplotlib
import matplotlib.pyplot as plt
import operator
from os import listdir
import time
初始化数据集
def createDataSet():
group = array([[1.0, 1.1], [1.0, 1.0],
[0, 0], [0, 0.1],
[2, 1.0], [2.1, 0.9],
[0.3, 0.0], [1.1, 0.9],
[2.2, 1.0], [2.1, 0.8],
[3.3, 3.5], [2.1, 0.9],
[2, 1.0], [2.1, 0.9],
[3.5, 3.4], [3.6, 3.5]
])
return group
#自己写的画图函数,每次都会画出初始数据集的点(红色),和要观察的点。
def show(data,color=None):
if not color:
color=‘green‘
group=createDataSet()
fig = plt.figure(1)
axes = fig.add_subplot(111)
axes.scatter(group[:, 0], group[:, 1], s=40, c=‘red‘)
axes.scatter(data[:, 0], data[:, 1], s=50, c=color)
plt.show()
代码取自机器学习实战第二章,在此加上我对这些代码的理解
def distEclud(vecA, vecB):
return sqrt(sum(power(vecA - vecB, 2))) #计算两点之间的欧氏距离
由于数据量级之间的差异会对影响度造成干扰,所以要对初始数据做数据归一化处理。
def randCent(dataSet, k): #数据归一化处理
n = shape(dataSet)[1]
centroids = mat(zeros((k, n))) # create centroid mat
for j in range(n): # create random cluster centers, within bounds of each dimension
minJ = min(dataSet[:, j])
rangeJ = float(max(dataSet[:, j]) - minJ)
centroids[:, j] = mat(minJ + rangeJ * random.rand(k, 1))
return centroids
shape(dataSet)是numpy库的一个方法,返回的是一个n维矩阵依次的维度。比如dataset=[[1,2,3],[2,4,5]] 的话,那么shape(dataset)=(2,3)
mat 方法是初始化矩阵
接下来是kmeans函数
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent): #参数dataSet是待聚类数据矩阵,k是聚类类数
m = dataSet.shape[0] #训练集中含有点的个数
clusterAssment = zeros((m, 2)) #初始化结果集,个数等于训练集中点的个数
centroids = createCent(dataSet, k)
# print centroids
# show(centroids) #matplotlib画图展示训练数据分布
clusterChanged = True #标记参数,用来检测每次循环后质心位置是否还会发生变化
while clusterChanged:
clusterChanged = False
for i in range(m):
point = dataSet[i, :] # 遍历数据集中的每个点
mindist = inf #inf 是Python中的正无穷
minindex = -1 #随机定义一个序号,此序号用来表示每个点与哪个质心的距离最近,是质心的序号,初始随便取个负数就好
for n in range(k):
heart = centroids[n, :] # 遍历每个质心
distance = distMeas(point, heart) # 求点与质心距离
if distance < mindist: #如果此质心的距离比当前最小距离小
mindist = distance # 更新最小距离mindist
minindex = n # 更新最小距离的质心序号
if clusterAssment[i, 0] != minindex: clusterChanged = True 如果质心的序号发生变化,改变标记数据
clusterAssment[i, :] = minindex, mindist ** 2 # 将第i个点存为(最近质心序号,此点到质心距离的平方)
# print clusterAssment
for cent in range(k):#遍历数据集,更新质心的位置
ptsInClust = dataSet[(clusterAssment[:, 0] == cent)] # 取出该质心绑定的点
# print ptsInClust
if len(ptsInClust):
centroids[cent, :] = mean(ptsInClust, axis=0) # 取出点的均值
else:
centroids[cent, :] = array([[0, 0]])
show(centroids,color=‘green‘) #作图画出此次循环后质心的变化情况
# print centroids
# print "----------------"
# show(centroids)
return centroids, clusterAssment #返回质心,以及各个点的信息
centroids, clusterAssment=kMeans(createDataSet(),4) #聚类为4类
show(centroids,color=‘yellow‘) #聚类结果展示为黄色点
图片
初始数据集以及初始随机选取质心
一种结果比较完美
尝试几次会出现以下不尽如人意的结果
以上就是kmeans的具体实现方法,但这个方法并不尽人意,多次执行会发现聚类得到的点并不稳定,也不是每次都能得到我们想要的最佳结果,这是因为这个算法只能达到局部最优,不能保证全局最优,而这个原因就在于我们不能保证我们出是选取到的点是最佳的点。当然也是有改进方法的,我会继续更新下一节二分 k-均值算法
k-Means 算法分析