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-均值算法

 

 

 









 

posted @ 2016-11-17 17:25  GreadLoveJM  阅读(971)  评论(0编辑  收藏  举报