zoukankan      html  css  js  c++  java
  • 机器学习——聚类算法

    本文主要讲解的聚类算法有:k均值算法、均值漂移算法、凝聚层次算法、DBSCAN密度聚类算法,还介绍了聚类算法性能指标——轮廓系数。

      聚类(cluster)与分类(class)不同,分类是有监督学习模型,聚类属于无监督学习模型。聚类讲究使用一些算法把样本划分为n个群落。一般情况下,这种算法都需要计算欧几里得距离

    $$P(x_1) - Q(x_2): |x_1-x_2| = sqrt{(x_1-x_2)^2} \
    P(x_1,y_1) - Q(x_2,y_2): sqrt{(x_1-x_2)^2+(y_1-y_2)^2} \
    P(x_1,y_1,z_1) - Q(x_2,y_2,z_2): sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2} \$$

    欧氏距离:用两个样本对应特征值之差的平方和的平方根,来表示这两个样本的相似性。

    K均值算法

    第一步:随机选择k个样本作为k个聚类的中心,计算每个样本到各个聚类中心的欧氏距离,将该样本分配到与之距离最近的聚类中心所在的类别中。

    第二步:根据第一步所得到的聚类划分,分别计算每个聚类的几何中心,将几何中心作为新的聚类中心,重复第一步,直到计算所得几何中心聚类中心重合或接近重合为止

    注意:

    1. 聚类数$k$必须事先已知。借助某些评估指标(欧式距离),优选最好的聚类数。

    2. 聚类中心的初始选择会影响到最终聚类划分的结果。初始中心尽量选择距离较远的样本。

    K均值算法相关API:

    import sklearn.cluster as sc
    
    model = sc.KMeans(n_clusters=4)     # n_clusters: 聚类数
    # 训练模型,不断调整聚类中心,直到最终聚类中心稳定则聚类完成
    model.fit(x)
    centers = model.cluster_centers_    # 获取训练结果的聚类中心
    labels = model.labels_              # 每个样本的聚类的类别标签

    案例:加载multiple3.txt数据集,基于K均值算法完成样本的聚类。

    import numpy as np
    import sklearn.cluster as sc
    import matplotlib.pyplot as plt
    
    x = np.loadtxt('../machine_learning_date/multiple3.txt', delimiter=',')
    model = sc.KMeans(n_clusters=4)     # 构建质心数量为4的聚类模型
    model.fit(x)                        # 训练模型
    pred_y = model.labels_              # 返回每个样本的聚类的类别标签: 0/1/2/3
    centers = model.cluster_centers_    # 返回所有的聚类中心样本
    print(centers)
    # 绘制分类边界线
    n = 500
    l, r = x[:, 0].min() - 1, x[:, 0].max() + 1
    b, t = x[:, 1].min() - 1, x[:, 1].max() + 1
    # 生成网格坐标矩阵
    grid_x = np.meshgrid(np.linspace(l, r, n), np.linspace(b, t, n))
    # 按列拼接数组
    flat_x = np.column_stack((grid_x[0].ravel(), grid_x[1].ravel()))
    flat_y = model.predict(flat_x)
    grid_y = flat_y.reshape(grid_x[0].shape)
    
    plt.figure('K-Means Cluster', facecolor='lightgray')
    plt.title('K-Means Cluster', fontsize=14)
    plt.xlabel('x', fontsize=14)
    plt.ylabel('y', fontsize=14)
    plt.tick_params(labelsize=10)
    plt.pcolormesh(grid_x[0], grid_x[1], grid_y, cmap='gray')
    plt.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg', s=80)
    plt.scatter(centers[:, 0], centers[:, 1], c='red', marker='+', s=500)
    
    plt.show()

    图像量化

      K-Means聚类算法可以应用于图像量化领域。通过K-Means算法可以把一张图像所包含的颜色值进行聚类划分,求每一类别的平均值后再重新生成新的图像。可以达到图像降维的目的。这个过程称为图像量化。图像量化可以更好的保留图像的轮廓,降低机器识别图像轮廓的难度。

    import sklearn.cluster as sc
    import matplotlib.pyplot as plt
    import scipy.misc as sm
    
    
    # 通过K均值聚类量化 图像中的"颜色"
    def quant(image, n_clusters):
        # x代表所有图片像素点的亮度值数组
        x = image.reshape(-1, 1)
        model = sc.KMeans(n_clusters=n_clusters)
        model.fit(x)
        # 当n_clusters=2时,label含:0/1
        # 当n_clusters=3时,label含:0/1/2
        # 当n_clusters=4时,label含:0/1/2/3
        y = model.labels_
        # 获取聚类中心 [30, 70, 110, 190]
        centers = model.cluster_centers_.ravel()        # 获取质心并变为一维数组
        return centers[y].reshape(image.shape)
    
    # 读取灰度图
    original = sm.imread('../machine_learning_date/lily.jpg', True)
    quant2 = quant(original, 2)
    quant3 = quant(original, 3)
    quant4 = quant(original, 4)
    plt.figure('Image Quant', facecolor='lightgray')
    plt.subplot(221)
    plt.title('Original', fontsize=14)
    plt.axis('off')
    plt.imshow(original, cmap='gray')
    plt.subplot(222)
    plt.title('Quant-2', fontsize=14)
    plt.axis('off')
    plt.imshow(quant2, cmap='gray')
    plt.subplot(223)
    plt.title('Quant-3', fontsize=14)
    plt.axis('off')
    plt.imshow(quant3, cmap='gray')
    plt.subplot(224)
    plt.title('Quant-4', fontsize=14)
    plt.axis('off')
    plt.imshow(quant4, cmap='gray')
    plt.tight_layout()
    plt.show()

    均值漂移算法

      假设在一个有N个样本点的特征空间,初始一个中心点,计算在设置的半径圆形空间内的所有点与中心点的向量,计算整个圆形空间内所有向量的平均值,得到一个偏移均值,将中心点移动到偏移值位置,重复移动,直到满足一定条件结束,最终移动的中心点就是聚类的中心,再根据每个样本距离各个中心的距离,选择最近聚类中心所属的类别作为该样本的类别。

    均值漂移算法的特点:

    1. 聚类数不必事先已知,算法会自动识别出统计直方图的中心数量。
    2. 聚类中心不依据于最初假定,聚类划分的结果相对稳定。
    3. 样本空间应该服从某种概率分布规则,否则算法的准确性会大打折扣。

    均值漂移算法相关API:

    # n_samples:样本数量
    # quantile:量化宽度
    # 计算出半径(带宽)
    bw = sc.estimate_bandwidth(x, n_samples=len(x), quantile=0.1) 
    # 均值漂移聚类器
    model = sc.MeanShift(bandwidth=bw, bin_seeding=True)
    model.fit(x)

    案例:加载multiple3.txt,使用均值漂移算法对样本完成聚类划分。

    """均值漂移"""
    import numpy as np
    import sklearn.cluster as sc
    import matplotlib.pyplot as plt
    
    x = np.loadtxt('../machine_learning_date/multiple3.txt', delimiter=',')
    # 构建聚类模型
    bw = sc.estimate_bandwidth(x, n_samples=len(x), quantile=0.2)   # 计算出半径(带宽)
    model = sc.MeanShift(bandwidth=bw, bin_seeding=True)
    model.fit(x)
    # 返回每个样本的聚类的类别标签: 0/1/2/3
    pred_y = model.labels_
    # 返回所有的聚类中心样本
    centers = model.cluster_centers_
    print(centers)
    # 绘制分类边界线
    n = 500
    l, r = x[:, 0].min() - 1, x[:, 0].max() + 1
    b, t = x[:, 1].min() - 1, x[:, 1].max() + 1
    grid_x = np.meshgrid(np.linspace(l, r, n), np.linspace(b, t, n))
    flat_x = np.column_stack((grid_x[0].ravel(), grid_x[1].ravel()))
    flat_y = model.predict(flat_x)
    grid_y = flat_y.reshape(grid_x[0].shape)
    
    plt.figure('K-Means Cluster')
    plt.title('K-Means Cluster', fontsize=14)
    plt.xlabel('x', fontsize=14)
    plt.ylabel('y', fontsize=14)
    plt.tick_params(labelsize=10)
    plt.pcolormesh(grid_x[0], grid_x[1], grid_y, cmap='gray')
    plt.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg', s=80)
    plt.scatter(centers[:, 0], centers[:, 1], c='red', marker='+', s=500)
    
    plt.show()

    凝聚层次算法

      首先假定每个样本都是一个独立的聚类,如果统计出来的聚类数大于期望的聚类数,则从每个样本出发寻找离自己最近的另一个样本,与之聚集,形成更大的聚类,同时令总聚类数减少,不断重复以上过程,直到统计出来的聚类数达到期望值为止。

    凝聚层次算法的特点:

    1. 聚类数必须事先已知。借助某些评估指标,优选最好的聚类数。

    2. 没有聚类中心的概念,因此只能在训练集中划分聚类,但不能对训练集以外的未知样本确定其聚类归属。

    3. 在确定被凝聚的样本时,除了以距离作为条件以外,还可以根据连续性来确定被聚集的样本。

    凝聚层次算法相关API:

    # 凝聚层次聚类器
    model = sc.AgglomerativeClustering(n_clusters=4)
    pred_y = model.fit_predict(x)

    案例:重新加载multiple3.txt,使用凝聚层次算法进行聚类划分。

    import numpy as np
    import sklearn.cluster as sc
    import matplotlib.pyplot as plt
    
    x = np.loadtxt('../machine_learning_date/multiple3.txt', delimiter=',')
    # 凝聚层次聚类器
    model = sc.AgglomerativeClustering(n_clusters=4)
    pred_y = model.fit_predict(x)        # pred_y为x的类别
    plt.figure('Agglomerative Cluster', facecolor='lightgray')
    plt.title('Agglomerative Cluster', fontsize=14)
    plt.xlabel('x', fontsize=14)
    plt.ylabel('y', fontsize=14)
    plt.tick_params(labelsize=10)
    plt.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg', s=80)
    plt.show()

    在确定被凝聚的样本时,除了以距离作为条件以外,还可以根据连续性来确定被聚集的样本

    """
    基于连续性近邻筛选器的凝聚层次算法
    """
    import numpy as np
    import sklearn.cluster as sc
    import sklearn.neighbors as nb
    import matplotlib.pyplot as plt
    
    n_samples = 500
    x = np.linspace(-1, 1, n_samples)
    y = np.sin(x * 2 * np.pi)
    n = 0.3 * np.random.rand(n_samples, 2)
    x = np.column_stack((x, y)) + n     # 按列拼接
    # 无连续性的凝聚层次聚类器
    model_nonc = sc.AgglomerativeClustering(linkage='average', n_clusters=3)
    pred_y_nonc = model_nonc.fit_predict(x)
    # 近邻筛选器
    conn = nb.kneighbors_graph(x, 10, include_self=False)
    # 有连续性的凝聚层次聚类器
    model_conn = sc.AgglomerativeClustering(
        linkage='average', n_clusters=3, connectivity=conn)
    pred_y_conn = model_conn.fit_predict(x)
    plt.figure('Nonconnectivity', facecolor='lightgray')
    plt.title('Nonconnectivity', fontsize=14)
    plt.xlabel('x', fontsize=14)
    plt.ylabel('y', fontsize=14)
    plt.tick_params(labelsize=10)
    plt.scatter(x[:, 0], x[:, 1], c=pred_y_nonc, cmap='brg', alpha=0.5, s=30)
    plt.figure('Connectivity', facecolor='lightgray')
    plt.title('Connectivity', fontsize=14)
    plt.xlabel('x', fontsize=14)
    plt.ylabel('y', fontsize=14)
    plt.tick_params(labelsize=10)
    plt.scatter(x[:, 0], x[:, 1], c=pred_y_conn, cmap='brg', alpha=0.5, s=30)
    plt.show()

    轮廓系数

    聚类性能的指标:同一个聚类内部的样本要足够密集,不同聚类之间样本要足够疏远。

    轮廓系数计算规则:针对样本空间中的一个特定样本,计算它与所在聚类其它样本的平均距离a,以及该样本与距离最近的另一个聚类中所有样本的平均距离b,该样本的轮廓系数为(b-a)/max(a, b),将整个样本空间中所有样本的轮廓系数取算数平均值,作为聚类划分的性能指标。

    轮廓系数的区间为:[-1, 1]。 -1代表分类效果差,1代表分类效果好。0代表聚类重叠,没有很好的划分聚类。

    轮廓系数相关API:

    import sklearn.metrics as sm
    # v:平均轮廓系数
    # metric:距离算法:使用欧几里得距离(euclidean)
    v = sm.silhouette_score(输入集, 输出集, sample_size=样本数, metric=距离算法)

    案例:输出KMeans算法聚类划分后的轮廓系数。

    # 打印平均轮廓系数
    print(sm.silhouette_score( x, pred_y, sample_size=len(x), metric='euclidean'))

    DBSCAN密度聚类算法

      DBSCAN是基于密度的聚类算法,通过将紧密相连的样本划为一类,这样就得到了一个聚类类别。通过将所有各组紧密相连的样本划为各个不同的类别,则我们就得到了最终的所有聚类类别结果。把具有足够高密度的区域划分为镞(同一类别的样本他们之间紧密相连,也就是说在该类别任意样本周围不远处一定有同类别的样本存在)。并可在噪声的空间数据库中发现形状的聚类。

    DBSCAN算法的特点:

    1. 密度聚类算法一般假定类别可以通过样本分布的紧密程度决定
    2. 事先给定的半径会影响最后的聚类效果,可以借助轮廓系数选择较优的方案。

    3. 根据聚类的形成过程,把样本细分为以下三类:

      外周样本:被其它样本聚集到某个聚类中,但无法再引入新样本的样本。

      孤立样本:聚类中的样本数低于所设定的下限,则不称其为聚类,反之称其为孤立样本。

      核心样本:除了外周样本和孤立样本以外的样本。

    DBSCAN聚类算法相关API:

    # DBSCAN聚类器
    # eps:半径
    # min_samples:聚类样本数的下限,若低于该数值,则称为孤立样本
    model = sc.DBSCAN(eps=epsilon, min_samples=5)
    model.fit(x)
    # 获取训练后所有聚类的核心样本的索引数组  
    # 可以以此作为掩码,获取所有的核心样本
    indices = model.core_sample_indices_
    # 每个样本的聚类类别标签  [0,1,2,3,0,1,2,3,0,1,2,3,-1]
    labels = model.labels_  # 会出现-1的情况,label=-1的样本就是孤立样本

    案例:修改凝聚层次聚类案例,基于DBSCAN聚类算法进行聚类划分,选择最优半径。

    import numpy as np
    import sklearn.cluster as sc
    import sklearn.metrics as sm
    import matplotlib.pyplot as plt
    
    x = np.loadtxt('../machine_learning_date/perf.txt', delimiter=',')
    epsilons, scores, models = np.linspace(0.3, 1.2, 10), [], []
    for epsilon in epsilons:
        # DBSCAN聚类器
        model = sc.DBSCAN(eps=epsilon, min_samples=5)
        model.fit(x)
        # 计算轮廓系数
        score = sm.silhouette_score(
            x, model.labels_, sample_size=len(x), metric='euclidean')
        scores.append(score)
        models.append(model)
    scores = np.array(scores)
    best_index = scores.argmax()  # 求出最大值的索引
    best_epsilon = epsilons[best_index]  # 最优半径
    best_score = scores[best_index]  # 最优轮廓系数
    best_model = models[best_index]
    print("最优半径", best_epsilon)   # 最优半径 0.7999999999999999
    print("最优轮廓系数", best_score)  # 最优轮廓系数 0.6366395861050828

    获取核心样本、外周样本、孤立样本。并且使用不同的点型绘图。

    core_mask = np.zeros(len(x), dtype=bool)
    core_mask[best_model.core_sample_indices_] = True
    offset_mask = best_model.labels_ == -1
    periphery_mask = ~(core_mask | offset_mask)
    plt.figure('DBSCAN Cluster', facecolor='lightgray')
    plt.title('DBSCAN Cluster', fontsize=14)
    plt.xlabel('x', fontsize=14)
    plt.ylabel('y', fontsize=14)
    plt.tick_params(labelsize=10)
    labels = best_model.labels_
    # 核心样本
    plt.scatter(x[core_mask][:, 0], x[core_mask][:, 1], c=labels[core_mask],
                cmap='brg', s=80, label='Core')
    # 外周样本
    plt.scatter(x[periphery_mask][:, 0], x[periphery_mask][:, 1], alpha=0.5,
                c=labels[periphery_mask], cmap='brg', marker='s', s=80, label='Periphery')
    # 孤立样本
    plt.scatter(x[offset_mask][:, 0], x[offset_mask][:, 1],
                c=labels[offset_mask], cmap='brg', marker='x', s=80, label='Offset')
    plt.legend()
    plt.show()

  • 相关阅读:
    linux目录跳转的好武器z.sh
    找工作的程序员必懂的Linux
    11-面向对象4
    10-面向对象3
    09-面向对象2
    08-面向对象1
    06-数组
    3.5-乘法运算器设计
    3.2-定点数补码加减运算器设计
    4.12-虚拟存储器
  • 原文地址:https://www.cnblogs.com/LXP-Never/p/12342000.html
Copyright © 2011-2022 走看看