美文网首页
机器学习----聚类

机器学习----聚类

作者: strive鱼 | 来源:发表于2019-01-15 18:52 被阅读0次

    接着机器学习系列文章的脚印,今天介绍一下机器学习的无监督算法--聚类, 内容主要包括以下几个部分:
    (1)常见的聚类方法的方法的通俗讲解和图片演示
    (2) 上述算法的数学公式简单展示和推导理解
    (3) 常见聚类算法的sklearn 的简单用法demo
    (4) 官方实例的 一个实际操作

    一、常见聚类方法/公式展示和简单推导

    1. k-means(k均值聚类)
    2. 基于密度的DBSCAN算法
    3. 用高斯混合模型(GMM)的最大期望(EM)聚类
    4. 凝聚层次聚类
    1. k-means(k均值聚类)
      (1) 初始化K个质心,质心个数的选择需要自己根据数据量定夺
      (2) 计算每一个数据点到k 个质心的距离,随即选择最短的距离,并将该点归为此质心
      (3)计算每一类中中心点作为新的中心点
      (4)重复以上步骤,直到每一类中心在每次迭代后变化不大为止。同时,也可以多次随机初始化中心点,然后选择运行结果最好的一个。

    优点:便捷性
    不足:最好可以之前预设好质心的个数,也就是簇的个数

    数学原理:本质上就是利用了欧式距离

    周志华西瓜书上关于k-means算法讲解

    2.基于密度的DBSCAN算法
    特点:
    (1) 聚类的时候不要确定质心(簇) 的个数
    (2) 最终的簇的个数也并不确定

    一些属性词的普适化解释

    • 核心点:以该点为圆心,EPS半径内的点的个数满足大于等于minpoints ,那么该点就是核心点
    • 边界点:以该点为圆心,EPS半径内的点的个数小于minpoints, 且,该点在上述核心点的EPS参数密度(就是上述核心点的圆圈里)里,这些点就是边界点 --下图黄色的点
    • 噪音点,既不是核心点,也不是边界点
      *ϵ-邻域:即对于样本点xi,和它的距离在ϵ之内的属于样本集D中的点的集合,
      即Nϵ(xj)={si∈D|dist(xi,xj)≤ϵ}
      *密度直达和密度可达:密度直达,假设核心点xi,在它的ϵ-邻域中存在xj,则xi和xj就是密度直达,同时,如果存在一个点集,n1,n2,n3,......nN,xi和其中的某一个点是密度直达,其中某一个点到xj是密度直达,那么就说xi 到xj 是密度可达
      *密度相连:对于样本点xj和xi若存在点xk使得xj和xi均可由xk密度可达,则称xj和xi密度相连,其实本质上是密度可达的双向性


    最终的聚类结果展示和说明

    如图算法自动将数据集分成了3簇,用三种颜色代表。每一簇内较大的点代表核心对象,较小的点代表边界点。黑色的点代表离群点或者叫噪声点。

    优点
    (1)不需要指定cluster的数目
    (2) 参数较少,只有两个
    (3)不受数据集点的分布形状限制,这样避免了k-means算法带来的分类误差


    (4)可以识别出噪音,且对噪音并不敏感

    缺点
    (1)DBSCAN的聚类效果收到距离公式的选择,一般会选择采用欧式距离,对于高纬度的数据,会有”维度灾难“
    (2)该方法不适合于密度差异很大的数据集,这样会导致半径和minpoints的选择较为困难

    周志华西瓜书算法讲解


    上述算法的理解难点是""和Ck的理解,其中,前一个符号的含义是取两者的差集,后者本质上就是取的交集作为一个簇

    3.用高斯混合模型(GMM)的最大期望(EM)聚类
    这个算法比较难以理解,在进行该算法之前,需要理解预备知识

    • 数学期望(离散)
      设离散型随机变量X的分布为



      那么其数学期望为
    • 数学期望(连续型)


    • 随机变量的方差



      标准差为其二次方根

    • 正态分布


    • 概率密度函数


      其中 即为协方差
    • 协方差


    • 多维高斯分布对应的概率密度函数



      高斯混合分布,其实本质上是多维的高斯分布,其中结合了朴素贝叶斯,极大似然法等。首选我们要了解聚类的目的就是将数据分到其本该归属的族内

      在周志华的书中对于高斯分布做了如下的解释和定义

    看到上述高斯混合分布的公式,是不是感觉到很难理解,α“混合系数”到底代表的是什么?另外,高斯混合分布怎么和朴素贝叶斯联系到一起的呢?

    我们先来回答第二个问题,我们聚类的目的就是要知道数据属于哪一簇,也就是zj的下标是?


    上式子中的分母是不是跟高斯混合分布一模一样,这里αl就是高斯混合分布中的混合系数,那么回答第一个问题,混合系数有没有比较直观的理解方式呢?接下来我们来看一下全概率公式

    P(B)=P(A1)P(B|A1)+ P(A2)P(B|A2)+…+ P(An)P(B|An)
    如果将A1,2,3,......n理解为多个簇,也就是多个高斯分布,是不是上述的分母和混合系数就可以理解了?对!混合系数就是每一个簇(高斯分布)出现的概率

    那我们怎么才能确定数据属于哪一个zj?也就是哪一个高斯成分呢?当然就是要求出上述的最大值,即上述9.30的最大值。我们想到用极大似然法


    关于极大似然估计的通俗详细理解,请看该位博主的文章,传送门:
    https://blog.csdn.net/zengxiantao1994/article/details/72787849

    为什么要选择使用EM算法?(Expectation-maximization algorithm,又译期望最大化算法),我个人的理解是,把xj看作是一组要进行分类(这里是找到对应的高斯分布),那么它直接对应的是zj(某一个高斯分布),而并非直接对应到该zj的参数,这有点像复合函数,复合函数的求导,也是由内到外,一层一层的求偏导
    那我们就加入zj,来变EM算法,在此之前,还需要了解到

    • jensen 不等式

      回顾优化理论中的一些概念。设f是定义域为实数的函数,如果对于所有的实数x,
    ,那么f是凸函数。当x是向量时,如果其hessian矩阵H是半正定的( ),那么f是凸函数。如果 或者

    ,那么称f是严格凸函数。

    如果f是凸函数,X是随机变量,那么



    知道了上述的不等式后,我们来看极大似然法的EM求解



    从(2)到(3)式是由上述的jensen不等式得到的,



    周志华书中的伪代码:


    4.层次聚类
    (1)示意图:


    (2)基本思想

    1.初始化–>把每个样本归为一类,计算每两个类之间的距离,也就是样本与样本之间的相似度;
    2.寻找各个类之间最近的两个类,把他们归为一类(这样类的总数就少了一个);
    3.重新计算新生成的这个类与各个旧类之间的相似度;
    4.重复2和3直到所有样本点都归为一类,结束。

    (3)周志华书的伪代码


    (4)优缺点:
    优点:
    不需要知道有多少个簇
    对于距离度量标准的选择并不敏感
    缺点:
    效率低

    二、skelarn 简单介绍demo
    这一part 主要介绍常用的聚类方法k-means 和 DBSCAN 其他聚类算法大家感兴趣可以看官方文档,毕竟精力有限,不在此进行总结
    传送门:https://blog.csdn.net/chinachenyyx/article/details/75299043

    1. kmeans 聚类
    """
    sklearn 官方文档
    """
    
    """
    1.首先是k-means聚类
    
    (1)相关的参数
    n_clusters  初始化质心的个数,默认为8
    
    init  设定选择质心的方法,可接受三种,k-means++,random,ndarray 
    第一种官方解释为最快
    第二种为随机选取observations(统计学中的体量,其实就是数据量),或者rows
    第三种为数组形式,若为数组需要给出shape 
    
    n_init 每次会选取k个质心进行训练,默认为10 代表,会选择10次,每次会初始化不同的k个质心
    
    max_iter 最大迭代次数  tol 容忍度,即可以接受的最大误差值,是停止迭代的标志 默认为1e-4
    
    precompute distances 是否需要提前计算距离,这个参数会在空间和时间之间做权衡,如果是True 会把整个距离矩阵都放到内存中,
    auto 会默认在数据样本大于featurs*samples 的数量大于12e6 的时候False,False 时核心实现的方法是利用Cpython 来实现的
    
    verbose 冗长模式,可以忽略。 random_state 整型 不太理解
    
    copy_x 是否修改数据的一个标记,如果True,即复制了就不会修改数据
    
    algorithm k-means 的实现算法, 可接受三种,auto,full,elkan, 其中full 表示EM 算法
    
    (2)相关属性
    cluster_centers_  质心的coordinates(坐标) 
    
    labels_ 每一个点的标签属性
    
    inertia_  所有的样本到其最近的cluster_center 的距离之和
    
    n_iter_  从开始到结束迭代运行的次数 
    
    """
    
    from sklearn.cluster import KMeans
    import numpy as np
    x=np.array([[1,2],[1,4],[1,0],[4,2],[4,4],[4,0]])
    kmeans=KMeans(n_clusters=2,random_state=0).fit(x)
    #print (kmeans.labels_)#返回的是[0,0,0,1,1]
    y=[[0,0],[4,4]]
    #print (kmeans.fit_predict(y))#返回的是对应样本所属簇心的索引值,也就是labels 的索引值,因此返回的是[0,1]
    #print (kmeans.predict(y))#返回的是样本所属的质心,因此返回为[0,0],注意和上述的fit_predict进行对比
    #print (kmeans.get_params()) 以字典的形式返回所有的参数名称以及对应的值
    #print (kmeans.fit_transform(y)) 我的理解是计算样本到对应簇心的距离,随后按照质心的维度进行拆解,返回的是矩阵,该例子返回的是2*2的矩阵
    #print (kmeans.transform(y)) transform x to a cluster-distince space  转置
    #print (kmeans.score(y))  Opposite of the value of X on the K-means objective.
    
    
    
    #下面是官方的demo
    #传送门:https://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_assumptions.html
    """
    文档对于该实例的展示用途如下:
    这个例子是为了说明k-means会产生不直观的、可能是意料之外的集群的情况。
    在前三个图中,输入数据不符合k-means make的一些隐含假设,因此产生了不希望出现的集群。
    最后一个图中,k-means返回直观的集群,尽管大小不均匀
    """
    
    import numpy  as np
    import matplotlib.pyplot as plt
    from sklearn.cluster import KMeans
    from sklearn.datasets import make_blobs#对于该数据集合重要的参数就是n_samples 数据集个数,n_features 属性的个数,centers 簇的个数,random_state 随机初始化质心数量
    plt.figure(figsize=(12,12))
    
    n_samples=1500
    random_state=170
    x,y=make_blobs(n_samples=n_samples,random_state=random_state)#x为样本集合,y为对应的标签集合
    #print(x)
    """
    # Incorrect numberr of cluster
    y_pred=KMeans(n_clusters=2,random_state=random_state).fit_predict(x)
    print (y_pred)
    plt.subplot(221) #1代表图形显示的位置索引,产生4张图再一块画布上,显示的位置为1,后边三张图一次为2,3,4
    plt.scatter(x[:,0],x[:,1],c=y_pred)
    plt.title ('Incorrect Number of Blobs')
    plt.show()
    
    该图的错误性在于初始质心选择不当所致,应该至少为3个
    """
    """
    # Anisotropicly distributed data
    transformation = [[0.60834549, -0.63667341], [-0.40887718, 0.85253229]]
    x_aniso = np.dot(x, transformation)
    y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(x_aniso)
    plt.subplot(222)
    plt.scatter(x_aniso[:, 0], x_aniso[:, 1], c=y_pred)
    plt.title("Anisotropicly Distributed Blobs")
    plt.show()
    该示例聚类失败的原因是异方性,我的个人理解就是数据的离散性不够
    """
    
    """
    x_varied,y_varied=make_blobs(n_samples=n_samples,cluster_std=[1.0,2.5,0.5],random_state= random_state,n_features=2)
    #cluster_std:每个簇的标准差,衡量某簇数据点的分散程度(见效果图) float or sequence of floats, optional (default=1.0)
    y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(x_varied)
    plt.subplot(223)
    plt.scatter(x_varied[:, 0], x_varied[:, 1], c=y_pred)
    plt.title("Unequal Variance")
    plt.show()
    
    该示例失败的原因是,每一个簇心覆盖的点的离散程度是不同的,有的簇覆盖的数据分散性大,有的分散性较小
    """
    
    """
    import numpy as np
    array1=np.array([[1,2,3],[4,5,6]])#2*3
    array2=np.array([[7,8,9],[10,11,12]])#2*3
    #print (np.stack(a,1))列变为行
    [[1 4]
     [2 5]
     [3 6]]
    arr1 = np.array([[1,2,3],[4,5,6]])
    arr2 = np.array([[7,8,9],[10,11,12]])
    res = np.vstack((arr1, arr2))
    print (res)
    [[ 1  2  3]
     [ 4  5  6]
     [ 7  8  9]
     [10 11 12]]
    arr11 = np.array([[1, 2], [3, 4], [5, 6]])
    arr22 = np.array([[7, 8], [9, 0], [0, 1]])
    res_cop = np.hstack((arr1, arr2))
    print (res_cop)
    [[ 1  2  3  7  8  9]
     [ 4  5  6 10 11 12]]
     """
    
    """
    # Unevenly sized blobs
    x_filtered = np.vstack((x[y == 0][:500], x[y == 1][:100], x[y == 2][:10]))
    y_pred = KMeans(n_clusters=3,random_state=random_state).fit_predict(x_filtered)
    plt.subplot(224)
    plt.scatter(x_filtered[:, 0], x_filtered[:, 1], c=y_pred)
    plt.title("Unevenly Sized Blobs")
    plt.show()
    该方法的结果大致可以接受,但唯一的不足就是每一簇的数据个数不太均匀,有些多,有些少
    """
    

    2.DBSCAN 聚类

    #下面是DBSCN聚类
    
    """
    2.DBSCAN聚类
    
    
    (1) 相关参数
    
    传送门:https://scikit-learn.org/0.15/modules/generated/sklearn.cluster.DBSCAN.html
    看了文章上述对于DBSCAN的解释,会对其参数了解起到一定作用
    eps: 说白了就是核心点对应的ϵ-邻域的半径,因此eps过大,则更多的点会落在核心对象的ϵ-邻域,此时我们的类别数可能会减少,
    本来不应该是一类的样本也会被划为一类。反之则类别数可能会增大,本来是一类的样本却被划分开。
    min_samples:就是文章上述所说的minpoints,默认为5
    metric: 点距离的计算方法,常用的是欧式距离(euclidean),曼哈顿距离(manhattan)
    random_state: 初始化质心,跟上述k-means的参数一样
    
    
    (2)相关使用方法,属性这块感觉没什么用,有兴趣的同学可以自己根据上边传送门学习
    fit(X) 训练样本集
    fit_predict(X) 预测样本集,Performs clustering on X and returns cluster labels.
    get_params() get parameters for this estimator 
    """
    
    #下面是官方给出的demo 和自己的理解注释
    
    
    import numpy as np
    from sklearn.cluster import DBSCAN
    from sklearn.datasets.samples_generator import make_blobs#自带数据库
    from sklearn.preprocessing import StandardScaler#对原始的数据进行预处理,使得离散程度减弱,更加复合高斯分布\
    import matplotlib.pyplot as plt
    """
    对应的参数为
    parameters:
    with_mean boolean 为真的时候,表明center the data before scaling 就是先平均再规范化
    with_std:boolean If True, scale the data to unit variance (or equivalently, unit standard deviation).
    意思是为真的时候计算方差和标准差
    """
    centers = [[1, 1], [-1, -1], [1, -1]]
    x, labels_true = make_blobs(n_samples=750, centers=centers, cluster_std=0.4,random_state=0)
    #print (x)
    #print (labels_true)0,1,2 组成的1维数据标签
    x=StandardScaler().fit_transform(x)#该步骤的主要作用就是样本集的预处理,这里要强调transform()和fit_transform()的区别
    """
    通俗解释传送门:https://blog.csdn.net/quiet_girl/article/details/72517053
    """
    ###########
    #compute DBSCAN
    db=DBSCAN(eps=0.3, min_samples=10).fit(x)
    #print (db.labels_) labels_属性返回每一个样本划分的标签
    #print (db.core_sample_indices_) #返回每个样本索引,该例子就是0-749
    core_samples_mask = np.zeros_like(db.labels_,dtype=bool)#np.zeros_like 返回参数同shape的0组成的数组,该例子返回bool型,因此返回的都为False
    #print (core_samples_mask)
    core_samples_mask[db.core_sample_indices_] = True
    #print (core_samples_mask)
    labels = db.labels_
    #print (labels)
    n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)#4-1
    #print (n_clusters_)
    unique_labels=set(labels)
    colors = plt.cm.Spectral(np.linspace(0, 1, len(unique_labels)))
    """
    对于上述的理解给出几个例子
    >>> np.linspace(2.0, 3.0, num=5)
        array([ 2.  ,  2.25,  2.5 ,  2.75,  3.  ])
    >>> np.linspace(2.0, 3.0, num=5, endpoint=False)
        array([ 2. ,  2.2,  2.4,  2.6,  2.8])
    >>> np.linspace(2.0, 3.0, num=5, retstep=True)
        (array([ 2.  ,  2.25,  2.5 ,  2.75,  3.  ]), 0.25)
    colors = plt.cm.Spectral(np.arange(5)) 产生5种不同颜色
    """
    for k,col in zip(unique_labels,colors):
        if k==-1:
            # black used for noise
            col='k'
        class_member_mask=(labels==k)
        xy = x[class_member_mask & core_samples_mask] #通过 &,|来进行一个样本的分类
        plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=col,
                 markeredgecolor='k', markersize=14)
        xy = x[class_member_mask & ~core_samples_mask]
        plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=col,
                 markeredgecolor='k', markersize=6)
    
    plt.title('Estimated number of clusters: %d' % n_clusters_)
    plt.show()
    

    关于机器学习聚类的总结接近尾声了,下一篇是机器学习系列的最后一种常见算法PCA,之后该机器学习--sklearn就结束了,下一系列承接这一系列进行github/kaggle 上面的实操练习,同时搭配github上目前流行的 机器学习100天(大家感兴趣可以先行学习,非常好的资源,传送门:https://github.com/Avik-Jain/100-Days-Of-ML-Code, 什么?看英文头晕,最近偶然发现了授权中文翻译版!!良心资源,https://github.com/Avik-Jain/100-Days-Of-ML-Code/blob/master/Code/Day%201_Data%20PreProcessing.md

    相关文章

      网友评论

          本文标题:机器学习----聚类

          本文链接:https://www.haomeiwen.com/subject/ilkhrqtx.html