天天看点

机器学习算法 - k-means Clustering K均值聚类

k-means Clustering即K均值聚类算法是一类运用广泛的聚类算法。

相关定义

聚类

聚类是指把对象划分为多个组或者“聚簇”,从而使得同组对象之间比较相似,而不同组对象之间差异较大。

因为聚类过程中,并没有输入和待聚类对象之间的联系信息,因此聚类通常被看做无监督学习。

k-means算法是一种简单的聚类算法,主要通过迭代来将数据集分类。

算法描述

数学描述

算法的输入对象可以看做是 d 维向量空间的一些点,即对集合D={xi|i=1,2,3,...,n}进行聚类,并且其中 xi∈Rd 表示第i个数据点。而k-means聚类则是对D中的所有数据点进行处理,聚类中心可以表示为 C={Ki|i=1,2,...,k} ,并且将每个数据点可以记为 xi∈S(Kj) 即表示对第 i 个数据点属于聚类中心Kj。

对于聚类算法,通常需要定义一种依据来判断每个数据点属于哪个聚类中心,而这个依据通常被称为代价函数。在一般情况下,我们选取的聚类函数通常如下:

Cost=Σki=1Σx∈S(Ki)∥x−μi∥2

其中 μi 是属于第i个聚类 S(Ki) 的对象点的均值,即聚类中心 Ki 。聚类的目标则是最小换这个代价函数,使得每个数据点 xi 和最近的聚类中心 Kj 的欧几里得距离的平方和最小。

算法步骤

输入:数据集 D ,聚类数k

输出:聚类集合 C ,聚簇成员向量m⃗ 

  1. 创建k个点作为起始质心
  2. 当任意一个点的簇分配结果发生改变时
    • 对数据集中的每个数据点,对每个质心,计算质心与数据点之间的距离
    • 将数据点分配到离它距离最近的簇
    • 对每一个簇,计算簇中所有的点的均值并将均值作为新的聚类中心

至于算法中怎么找到初始的聚类中心,怎么计算,度量函数的选择,在后面都会提到。

程序

python

相关辅助函数

from numpy import *

def loadDataSet(filename) :
    dataMat = []
    fr = open(filename) :
    for line in fr.readlines() :
        curLine = line.strip().split('\t')
        fltLine = map(float, curLine)
        dataMat.append(fltLine)
    return dataMat

#Eclud Distance
def distEclud(vecA, vecB):
    return sqrt(sum(power(vecA - vecB, )))

#Initial Random Clustering Centroids    
def randCent(dataSet, k):
    n = shape(dataSet)[]
    centroids = mat(zeros((k,n)))
    for j in range(n):
        minJ = min(dataSet[:,j])
        rangeJ = float(max(dataSet[:,J]) - minJ)
        centroids[:,J] = minJ + rangeJ * random.rand(k,)
    return centroids
           

这个是两个辅助的函数,第一个函数定义了我们之前说的常用的一个度量——欧几里得距离,简称欧式距离。第二个辅助函数是用来随机初始化聚类中心的函数,其中centroids是聚类中心,dataSet是数据集合,k是聚类中心的数量,其中随机化的方法是找到数据的最小值和最大值,再在这两个数之间产生k个随机的值。

K-means算法

def kMeans(dataSet, k, distMeas = distEclud, createCent = randCent) :
    m = shape(dataSet)[]
    clusterAssment = mat(zeros((m,)))
    centroids = createCent(dataSet, k)
    clusterChanged = True
    while clusterChanged:
        clusterChanged = False
        for i in range(m) :
            minDist = inf
            minIndex = -
            for j in range(k) :
                distJI = distMeas(centroids[j,:],dataSet[i,:])
                if distJI < minDist :
                    minDist = distJI
                    minIndex = j
            if clusterAssment[i,] != minIndex:
                clusterChanged = True
            clusterAssment[i,:] = minIndex, minDist**

        for cent in range(k) :
            ptsInClust = dataSet[nonzero(clusterAssment[:,].A == cent)[]]
            centroids[cent,:] = mean(ptsInClust, axis = )

    return centroids, clusterAssment
           

在这一部分算法中,按照上面的说明,总共包含了三部分内容,即初始化聚类中心,寻找对于每个目标点最近的聚类中心,更新聚类中心的位置,当且仅当聚类中心收敛时,停止算法。我个人认为这里应当简单的加上停止算法,当迭代一定的次数时。

算法初始化了一个m行,2列的一个矩阵clusterAssment,这个矩阵的每一行都对应了一个目标点,而每一行的第一个位置记录了聚类中心,第二个位置记录了这个目标点到聚类中心的距离的平方。在判断聚类中心是否改变时,程序的判断依据是新的距离和clusterAssment里面储存的距离的对比。

程序的最后一部分内容是通过计算每个聚类中心所对应的目标点的值得均值, 来重新计算聚类中心。

算法的局限性

局部最优解

k-means算法在本质上属于非凸函数的贪婪下降求解算法, 因此在理论上,最后得到的收敛解都只是局部最优解而并非是全局最优解。并且是否最终能够取到全局最优解在一定程度上与初始的聚类中心的位置也是相关的,对相同的数据集,如果一开始选取的聚类中心不同,那么最终聚类出的结果可能不相同。

所以在解决这个问题上,主要是通过合理的选择初始化的聚类中心以及在算法上做优化防止出现局部最优解。

K的选取

在实际中,由于对数据集的分布情况缺乏先验的了解,因此有可能并不能预先知道

继续阅读