机器学习第九章——聚类

一、聚类任务

聚类试图将数据集中的样本划分为若干个通常是不相交的子集,每个子集称为一个“”(cluster).通过这样的划分,每个簇可能对应于一些潜在的概念。
聚类既能作为一个单独过程,用于找寻数据内在的分布结构,也可作为分类等其他学习任务的前驱过程

二、性能度量

好的聚类结果:“簇内相似度”(intra-cluster similarity)高且“簇间相似度”(inter-cluster similarity)低.
聚类性能度量大致有两类. 一类是将聚类结果与某个“参考模型”(reference model)进行比较,称为“外部指标”(external index);另一类是直接考察聚类结果而不利用任何参考模型,称为“内部指标”(internalindex).

外部指标:

对数据集D =\left \{ x_{1}, x_{2},. . . , x_{m} \right \},假定通过聚类给出的簇划分为C =\left \{ C_{1}, C_{2},. . . , C_{k} \right \},参考模型给出的簇划分为C^{*} =\left \{ C_{1}^{*}, C_{2}^{*},. . . , C_{s}^{*} \right \}.相应地,令\lambda\lambda ^{*}分别表示与C和C*对应的簇标记向量.我们将样本两两配对考虑,定义

  • Jaccard系数(Jaccard Coefficient,简称JC):JC=\frac{a}{a+b+c}
  • FM指数(Fowlkes and Mallows Index,简称FMI):FMI=\sqrt{\frac{a}{a+b}\cdot \frac{a}{a+c}}
  • Rand指数(Rand Index,简称RI):RI=\frac{2(a+d)}{m(m-1)}

上述性能度量的结果值均在 [0 1] 区间,值越大越好。

内部指标:

考虑聚类结果的簇划分C =\left \{ C_{1}, C_{2},. . . , C_{k} \right \},定义

dist(\cdot ,\cdot )用于计算两个样本之间的距离; \mu代表簇C的中心点\mu =\frac{1}{\left | C \right |}\sum_{1\leqslant i\leqslant \left | C \right |}

  • DB指数(Davies-Bouldin Index,简称DBI)DMI=\frac{1}{k}\sum_{i=1}^{k}\max_{j\neq i}\left ( \frac{\textup{avg}(C_{i})+\textup{avg}(C_{j})}{d_{\textup{cen}}(\mu _{i},\mu _{j})} \right )
  • Dunn指数(Dunn Index,简称DI)DI=\min_{1\leqslant i\leqslant k}\left \{ \min_{j\neq i}\left ( \frac{d_{\textup{min}}(C _{i},C _{j})}{\max_{1\leqslant l\leqslant k}\textup{diam}(C_{l})} \right ) \right \}

DBI的值越小越好,而DI 则相反,值越大越好.

三、距离计算

给定样本x_{i}=(x_{i1};x_{i2};...;x_{in})x_{j}=(x_{j1};x_{j2};...;x_{jn})

  • 闵可夫斯基距离”(Minkowski distance)

  • p=2时,欧氏距离(Euclidean distance) 

  • p=1时,曼哈顿距离(Manhattan distance)

“连续属性”(continuous attribute)在定义域上有无穷多个可能的取值

“离散属性”(categorical attribute)在定义域上是有限个取值

  • “有序属性”(ordinal attribute)能直接在属性值上计算距离(闵可夫斯基距离可用于有序属性)
  • “无序属性”(non-ordinalattribute)不能直接在属性值上计算距离

无序属性:

m_{u,a}表示在属性u上取值为a的样本数,m_{u,a,i}表示在第i个样本簇中在属性u上取值为a的样本数,k为样本簇数

VDM (Value Difference Metric)距离:

闵可夫斯基距离和VDM结合处理混合属性.n_{c}个有序属性、n-n_{c}个无序属性,不失一般性,令有序属性排列在无序属性之前,则

" 加权距离"(以加权闵可夫斯基距离为例):

四、原型聚类

原型聚类:先对原型进行初始化,然后对原型进行迭代更新求解.采用不同的原型表示、不同的求解方式,将产生不同的算法.

k均值算法:

给定样本集D =\left \{ x_{1}, x_{2},. . . , x_{m} \right \},“k 均值”(k-means)算法针对聚类所得簇划分C =\left \{ C_{1}, C_{2},. . . , C_{k} \right \}最小化平方误差

其中是簇C的均值向量

算法流程:

利用K-均值聚类算法对未标注数据分组:

import math
from numpy import *


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


'''
distEclud(vecA, vecB)函数计算两个向量的欧式距离
公式:sqrt((x1-x2)^2+(y1-y2)^2)
'''


def distEclud(vecA, vecB):
    return math.sqrt(sum(power(vecA - vecB, 2)))


'''
randCent()函数为给定数据集构建一个包含k个随机质心的集合。
随机质心必须要在整个数据集的边界之内,这可以通过找到数据集每一维的最小值和最大值来完成。
然后生成0到1.0之间的随机数并通过取值范围和最小值,以便确保随机点在数据的边界之内。
'''


def randCent(dataSet, k):
    n = shape(dataSet)[1]
    centroids = mat(zeros((k, n)))  # 创建存储k个质心的矩阵
    for j in range(n):  # 在边界范围内,随机生成k个质心
        minJ = min(dataSet[:, j])  # 边界的最小值
        rangeJ = float(max(dataSet[:, j]) - minJ)  # 边界范围
        centroids[:, j] = mat(minJ + rangeJ * random.rand(k, 1))
    return centroids


'''
K-Means算法:
两个必选参数:
dataSet:该参数为给定的数据集,
k:该参数为簇的数目,
两个可选的参数:
distEclud:计算两个向量组之间的距离,
randCent:创建初始质心;
该算法会创建k个质心,然后将每个点分配到最近的质心,再重新计算质心。
这个过程会重复多次,知道数据点的簇分配结果不再改变为止。
'''


def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
    # 确定数据集中数据点的总行数,shape()函数:查看矩阵或者数组的维数。
    m = shape(dataSet)[0]

    # 创建一个矩阵来存放每个点的簇分配结果,包含两列:一列是记录簇索引值,第二列是存储误差。
    # 误差是指当前点到簇质心的距离,后面将使用该误差来评价聚类的效果。
    clusterAssment = mat(zeros((m, 2)))

    # 通过功能函数randCent()随机获取K个质心,K由用户决定
    centroids = createCent(dataSet, k)

    # 标志变量:是否需要迭代的标志。
    # 初始为True,表示需要迭代,迭代的顺序为:计算质心-分配点到距离质心最短的簇中-重新计算
    # 直到所有数据点的簇分配结果不再改变为止
    clusterChanged = True

    # while循环:一直迭代循环计算:计算质心-分配-重新计算
    while clusterChanged:
        clusterChanged = False

        # 计算每个点到所有质心的距离,将每个点分配到距离其最近的质心所在的簇中
        for i in range(m):
            minDist = inf;
            minIndex = -1  # 质心的索引
            # for循环:寻找最近的质心
            for j in range(k):
                distJI = distMeas(centroids[j, :], dataSet[i, :])  # 计算数据点到每个质心的距离
                if distJI < minDist:  # 如果该距离比最小的距离还小,则更新minDist(最小距离)和最小质心的index(索引)
                    minDist = distJI;
                    minIndex = j
            # 如果任一点的簇分配结果发生改变,则更新标志的值,表示点的分配结果还未完成,需要继续迭代计算。
            if clusterAssment[i, 0] != minIndex: clusterChanged = True

            clusterAssment[i, :] = minIndex, minDist ** 2
        print("--------------------------------------------------")
        print(centroids)  # 打印所有质心

        # 遍历所有质心,并更新质心的取值。
        # 实现逻辑:首先通过数据过滤来获得给定簇的所有点。然后计算所有点的均值,该均值即为新的质心的坐标。
        #           axis=0表示沿矩阵的列方向进行均值计算;最后返回所有的类质心与点分配结果
        for cent in range(k):
            ptsInClust = dataSet[nonzero(clusterAssment[:, 0].A == cent)[0]]  # 获取该簇中所有的点
            centroids[cent, :] = mean(ptsInClust, axis=0)  # 将所有点的横、纵坐标的平均值赋给质心,质心的位置改变,mean()函数就是求平均值
    # 返回每个类的质心,以及该类所包含的所有的数据点
    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', '<r', 'pr']
    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', '<b', 'pb']
    for i in range(k):
        plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize = 7, color='orange')
    plt.show()


def main():
    dataMat = mat(loadDataSet('testSet.txt'))
    # 指定获取四个质心
    myCentroids, clustAssing = kMeans(dataMat, 4)
    # myCentroids, clustAssing = biKmeans(dataMat, 4)
    print("--------------------------------------------------")
    print("最终的质心列表:")
    print(myCentroids)
    print("--------------------------------------------------")
    show(dataMat, 4, myCentroids, clustAssing)


if __name__ == '__main__':
    main()

运行结果:

学习向量量化:

学习向量量化”(Learning Vector Quantization,简称LVQ)试图找到一组原型向量来刻画聚类结构,LVQ假设数据样本带有类别标记,学习过程利用样本的这些监督信息来辅助聚类.
LVQ算法描述:

高斯混合聚类:

高斯混合(Mixture-of-Gaussian)聚类采用概率模型来表达聚类原型

高斯分布概率密度函数

其中,\mu为n维均值向量,\Sigman\times n的协方差矩阵,因此高斯分布完全由这两个参数确定,就可以写成p(x\mid \mu,\Sigma)

高斯混合分布

若训练集D= \left \{x_{1},x_{2},...,x_{m} \right \}由上述过程生成,令随机变量z_{j}\in \left \{ 1,2,...,k \right \}表示生成样本x_{j},的高斯混合成分,其取值未知.显然, z_{j}的先验概率P(z_{j}=i)对应于\alpha _{i}(i=1,2,...,k)根据贝叶斯定理,z_{j}的后验分布对应于

高斯混合聚类算法:

五、密度聚类

密度聚类亦称“基于密度的聚类”(density-based clustering),假设聚类结构能通过样本分布的紧密程度确定.通常情形下,密度聚类算法从样本密度的角度来考察样本之间的可连接性,并基于可连接样本不断扩展聚类簇以获得最终的聚类结果.

DBSCAN基于一组“邻域”(neigh-borhood)参数(\epsilon, MinPts)来刻画样本分布的紧密程度.给定数据集 D= \left \{x_{1},x_{2},...,x_{m} \right \},定义下面这几个概念:

  • \epsilon-邻域:对x_{j}\in D,其\epsilon-邻域包含样本集D中与x_{j}的距离不大于\epsilon的样本,即;
  • 核心对象(core object):若x_{j}\epsilon-邻域至少包含MinPts个样本,即,则x_{j}是一个核心对象;
  • 密度直达(directly density-reachable):若x_{j}位于x_{i}\epsilon-邻域中,且x_{i}是核心对象,则称x_{j}x_{i}密度直达
  • 密度可达(density-reachable):对x_{i}x_{j},若存在样本序列p_{1},p_{2},...,p_{n},其中p_{1}=x_{i},p_{n}=x_{j},且p_{i+1}p_{i}密度直达,那么称x_{j}x_{i}密度可达
  • 密度相连(density-connected):对x_{i}x_{j},若存在x_{k}使得x_{i}x_{j}均由x_{k}密度可达,那么x_{i}x_{j}密度相连



DBSCAN算法:

六、层次聚类

层次聚类(hierarchical clustering)试图在不同层次对数据集进行划分,从而形成树形的聚类结构.数据集的划分可采用“自底向上”的聚合策略,也可采用“自顶向下”的分拆策略.
AGNES是一种采用自底向上聚合策略的层次聚类算法.它先将数据集中的每个样本看作一个初始聚类簇,然后在算法运行的每一步中找出距离最近的两个聚类簇进行合并,该过程不断重复,直至达到预设的聚类簇个数.

给定聚类簇C_{i}C_{j}:

以上三种算法,AGNES 算法被相应地称为“单链接”(single-linkage)、“全链接”(complete-linkage)或“均链接”(average-linkage)算法.

AGNES算法:








 

  • 21
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值