聚类方法简单总结

聚类概述

聚类(cluster)与分类(class)问题不同,聚类属于无监督学习模型,而分类属于有监督学习模型。聚类使用某种算法将样本分为N个群落,群落内部相似度较高,群落之间相似度较低。通常采用‘距离’来度量样本间的相似度,距离越小,相似度越高;距离越大,相似度越低。

相似度度量方式

  • 欧氏距离
    ∣ x 1 − x 2 ∣ = ( x 1 − x 2 ) 2 |x_1 - x_2| = \sqrt{(x_1 - x_2)^2} x1x2=(x1x2)2
  • 曼哈顿距离
    二维平面两点 a ( x 1 , y 1 ) 与 b ( x 2 , y 2 ) a(x_1, y_1)与b(x_2, y_2) a(x1,y1)b(x2,y2)两点间的曼哈顿距离为:
    d ( a , b ) = ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ d(a, b) = |x_1 - x_2| + |y_1 - y_2| d(a,b)=x1x2+y1y2
    将其扩展到N维空间, a ( x 1 , x 2 , . . . , x n ) a(x_1, x_2,... , x_n) a(x1,x2,...,xn) b ( y 1 , y 2 , . . . , y n ) b(y_1, y_2,... , y_n) b(y1,y2,...,yn)之间的曼哈顿距离为:
    d ( a , b ) = ∣ x 1 − y 1 ∣ + ∣ x 2 − y 2 ∣ + . . . + ∣ x n − y n ∣ = ∑ i = 1 n ∣ x i − y i ∣ d(a,b) = |x_1-y_1| + |x_2-y_2| + ... + |x_n-y_n| = \sum_{i=1}^{n}|x_i - y_i| d(a,b)=x1y1+x2y2+...+xnyn=i=1nxiyi
    在这里插入图片描述
    上图中,绿色线条表示为欧氏距离,红色表示曼哈顿距离,黄色和蓝色线条表示的为曼哈顿距离的等价长度。
  • 闵可夫斯基距离
    闵可夫斯基距离(Minkowski distance) 又称闵氏距离:
    D ( x , y ) = ( ∑ i = 1 n ∣ x i − y i ∣ p ) 1 p D(x,y) = (\sum_{i=1}^{n}|x_i - y_i|^p)^\frac{1}{p} D(x,y)=(i=1nxiyip)p1
    • p=1时,D为曼哈顿距离
    • p=2时,D为欧式距离
    • p → ∞ \rightarrow \infty 时,D为切比雪夫距离。
      因此,曼哈顿距离、欧氏距离都是闵可夫斯基距离的特殊形式。
  • 距离性质
    如果dist(x,y)度量标准为一个距离,则满足:
  • 非负性:dist(x,y) >= 0;
  • 同一性:dist(x,y) = 0时,x=y;
  • 对称性:dist(x,y) = dist(y,x);
  • 直递性:dist(x,y) <= dist(x,z) + dist(z,y)

聚类算法划分

  • 原型聚类
    原型聚类亦称“基于原型的聚类”(prototype-based clustering),此类算法假设聚类问题可以通过一组原型表示。一般,算法先对原型进行初始化,然后对原型进行迭代更新求解。采用不同的原型表示,将有不同的求解方式,对应不同的算法。最著名的算法就包括:K-Means。
  • 密度聚类
    密度聚类亦称“基于密度的聚类”(density-based clustering),此类算法假定聚类结构能够通过样本分布的紧密程度确定。一般,密度聚类算法从样本密度的角度考虑样本之间的连接性,并基于可连接样本不断扩展聚类簇以获得最终的聚类结果。比较著名的密度聚类算法有DBSCAN。
  • 层次聚类
    层次聚类(hierarchical clustering)试图在不同层次对数据集进行划分,从而形成树形的聚类结果。数据集的划分可以采用“自底向上”或者“自顶向下”的策略。常用的层次聚类算法包括凝聚层次算法等。

常用聚类算法

1)k均值聚类(K-Means clustering)算法是一种常用的、基于原型的聚类算法。执行步骤为:

  • 根据事先确定的聚类数,随机选择若干样本作为聚类中心,计算每个样本与每个聚类中心的欧式距离,离哪个聚类中心最近,就算哪个聚类中心的聚类簇,所有点有归属之后则一次聚类完成;
  • 然后再计算每个聚类的集合中心,如果几何中心与前一次的聚类中心不重合,就再次以新的几何中心作为新的聚类中心,重新划分聚类。
  • 重复以上过程,直至完成聚类后,各个聚类簇的中心与其所依据的聚类中心重合或者小于设定的阈值,表明聚类任务完成。在这里插入图片描述
    注意:
    1)聚类数目(K)必须事先确定;
    2)最终的聚类结果会因初始中心的选择不同而异,并且模型容易受到噪声点的干扰

K-Means简单演示

import numpy as np
import sklearn.cluster as sc
import sklearn.metrics as sm
import matplotlib.pyplot as plt

x = []
with open("D:/python/data/multiple3.txt", 'r') as f:
    for line in f.readlines():
        data = [float(substr) for substr in line.split(',')]
        x.append(data)
x = np.array(x)
print(x.shape)

# k均值聚类器
model = sc.KMeans(n_clusters=4) # n_clusters为事先预定的聚类簇数量
# 训练
model.fit(x)

cluster_labels_ = model.labels_ # 每一个点的聚类结果
cluster_centers_ = model.cluster_centers_ # 获得聚类几何中心
print('cluster_labels_: ', cluster_labels_)
print('cluster_centers_: ', cluster_centers_)

silhouette_score = sm.silhouette_score(x, cluster_labels_,
                                       sample_size=len(x),
                                       metric='euclidean' # 欧式距离度量方式
                                       )
print('silhouette_score: ', silhouette_score)

print('--------可视化--------')
plt.figure('K-Means Cluster', facecolor='lightgray')
plt.title('K-Means Cluster', fontsize=16)
plt.xlabel('x', fontsize=12)
plt.ylabel('y', fontsize=12)
plt.tick_params(labelsize=10)
plt.scatter(x[:,0], x[:,1], s=50, c=cluster_labels_, cmap='brg')
plt.scatter(cluster_centers_[:,0], cluster_centers_[:,1], marker='+',
            c='black', s=120, linewidths=3)
plt.show()

"""
cluster_labels_:  [2 2 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 1 1 3 0 2 1 3 0 2 1 3 0 2
 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1
 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 3 1 3 0 2 1 3 0 2 1 3 0 2 1 3
 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0
 2 2 3 0 2 1 3 0 2 1 3 1 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0 2
 1 3 0 2 1 3 0 2 1 3 0 2 1 3 0]
cluster_centers_:  [[7.07326531 5.61061224]
 [3.1428     5.2616    ]
 [1.831      1.9998    ]
 [5.91196078 2.04980392]]
silhouette_score:  0.5773232071896658
"""

在这里插入图片描述

特点

  • 优点
    • 原理简单,实现方便,收敛速度较快;
    • 聚类效果较好,模型可解释性强
  • 缺点
    • 需要事先预定聚类簇数量;
    • 初始中心选择对聚类效果有影响,可能得到局部最优解;
    • 对噪声敏感
  • 使用条件
    • 事先可以知道聚类数量
    • 数据分布具有明显的中心

2)噪声聚类DBSCAN(Density-Based Spatial Clustering of Applications with Noise)。执行步骤为:

  • 随机选择一个样本作为圆心,以事先确定的半径画圆,凡是圈中的样本点都被划分到与圆心样本同一个聚类,然后再以这些被圈中的样本点为圆心,以事先确定的半径画圆,不断加入新的样本,扩大聚类的规模,直至不再有新的样本加入,即完成一个聚类;
  • 重复以上的步骤直至所有的样本点划分完毕。
    在这里插入图片描述
    DBSCAN中,样本点分为三类:
  • 边界点:不能发展出新的样本点,但是属于一个聚类;
  • 噪声点:无法划分到某类中的点;
  • 核心点:除了边界点和噪声点都是核心点,其可以发展出新的样本点。
    在这里插入图片描述
    其中,样本点A、B属于可以发展出新的样本点的核心点,C是不可以发展出新的样本点的边界点;D由于无法划分到任何类别而被视为噪声点。

DBSCAN简单演示

import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as plt
import sklearn.metrics as sm

x = []
with open('D:/python/data/perf.txt', 'r') as f:
    for line in f.readlines():
        data = [float(substr) for substr in line.split(',')]
        x.append(data)
x = np.array(x)
print(x.shape)

# 模型超参数
radius = 0.8 # 邻域半径
min_samples = 5 # 聚类簇最少样本点数量

# 创建噪声密度聚类器
model = sc.DBSCAN(eps=radius, min_samples=min_samples)
# 训练模型
model.fit(x)
# 划分结果
cluster_labels_ = model.labels_
# 评价聚类模型
score = sm.silhouette_score(x, model.labels_,
                            sample_size=len(x),
                            metric='euclidean') # 轮廓系数
print('silhouette_score: ', score)
# silhouette_score:  0.6366395861050828
                           
# 区分三类样本
# 核心样本
core_mask = np.zeros(len(x), dtype=bool)
core_mask[model.core_sample_indices_] = True
# 噪声样本
offset_mask = cluster_labels_==-1
# 边界样本
border_mask = ~(core_mask | offset_mask)

print('--------可视化--------')
plt.figure('DBSCAN Cluster', facecolor='lightgray')
plt.title('DBSCAN Cluster', fontsize=18)
plt.xlabel('x', fontsize=12)
plt.ylabel('y', fontsize=12)
plt.tick_params(labelsize=8)
plt.grid(':')
labels = set(cluster_labels_)
cs = plt.get_cmap('brg', len(labels))(range(len(labels)))

# 核心点
plt.scatter(x[core_mask][:, 0],  
           x[core_mask][:, 1],  
           c=cs[cluster_labels_[core_mask]],
           s=80, label='Core')
# 边界点
plt.scatter(x[border_mask][:, 0],
           x[border_mask][:, 1],
           edgecolor=cs[cluster_labels_[border_mask]],
           facecolor='none', s=80, label='Periphery')
# 噪声点
plt.scatter(x[offset_mask][:, 0],
           x[offset_mask][:, 1],
           marker='D', c=cs[cluster_labels_[offset_mask]],
           s=80, label='Offset')
plt.legend()
plt.show().

在这里插入图片描述

特点

  • 优点
    • 不需要提前确定聚类簇数量;
    • 能够有效处理噪声点(因为当一个聚类簇的样本点数量少于阈值时会被当作噪声点处理);
    • 可以处理任何形状的空间聚类。
  • 缺点
    • 当数据量过大时,要求较大的内存支持I/O消耗很大;
    • 当空间聚类的密度不均匀时、聚类间距差别很大时,聚类效果有偏差;
    • 邻域半径和最少样本数量两个参数对聚类结果影响最大。
  • 何时选择噪声密度
    • 数据稠密、没有明显聚类中心;
    • 噪声数据较多;
    • 未知聚簇的数量

3)凝聚层次(Agglomerative)算法,执行步骤为:
首先将每个样本看作独立的聚类,如果聚类数大于预设的数值,则合并最近的样本作为一个新的聚类,如此反复迭代,不断扩大聚类规模的同时减少聚类的总数。直到聚类减少到预设数值为止。凝聚层次算法的核心是如何衡量不同的聚类簇之间的距离。

  • 以距离将凝聚层次算法分为
    • ward:默认选项,使用方差作为标准,假设簇A、簇B合并后使得所有簇的方差增加最小,则选择合并A、B;
    • average:将两个簇中所有点之间平均距离最小的两个簇合并;
    • complete:将两个簇中点的最大距离最小的两个簇合并

凝聚层次简单实现

import numpy as np
import sklearn.cluster as sc
import sklearn.metrics as sm
import matplotlib.pyplot as plt

x = []
with open("D:/python/data/multiple3.txt", 'r') as f:
    for line in f.readlines():
        data = [float(substr) for substr in line.split(',')]
        x.append(data)
x = np.array(x)
print(x.shape)

# 凝聚层次聚类器
model = sc.AgglomerativeClustering(n_clusters=4) # n_clusters为事先预定的聚类簇数量
# 训练
model.fit(x)
# 获取预测结果
cluster_labels_ = model.labels_ # 每一个点的聚类结果
silhouette_score = sm.silhouette_score(x, cluster_labels_,
                                       sample_size=len(x),
                                       metric='euclidean' # 欧式距离度量方式
                                       )
print('silhouette_score: ', silhouette_score)
# silhouette_score:  0.5736608796903743

print('--------可视化--------')
plt.figure('Agglomerative Cluster', facecolor='lightgray')
plt.title('Agglomerative Cluster', fontsize=16)
plt.xlabel('x', fontsize=12)
plt.ylabel('y', fontsize=12)
plt.tick_params(labelsize=10)
plt.scatter(x[:,0], x[:,1], s=50, c=cluster_labels_, cmap='brg')
plt.show()

在这里插入图片描述

特点

  • 需要事先确定分类簇数量(K);
  • 不依赖于中心点的划分,所以对于中心特征不明显的样本,划分效果更佳稳定;

聚类问题之评价指标

理想的聚类问题可以概括为:内密外疏,即同一聚类内部足够紧密,聚类之间足够疏远。学科中使用“轮廓系数”进行度量,见下图:
在这里插入图片描述
假设已经通过某算法,将样本点进行聚类,对于簇中每个样本,分别计算出轮廓系数。对于其中某个聚类簇而言:
a(i) = average(i向量到所有它属于的簇中其他点的距离)
b(i) = min(i向量到其他簇内所有点的平均距离)
则i向量的轮廓系数为:
S ( i ) = b ( i ) − a ( i ) m a x ( a ( i ) , b ( i ) ) S(i) = \frac{b(i) - a(i)}{max(a(i), b(i))} S(i)=max(a(i),b(i))b(i)a(i)
由公式可知:

  • b(i) >> a(i)时,S(i) → 1 \rightarrow 1 1,聚类效果最好;
  • b(i) << a(i)时,S(i) → − 1 \rightarrow -1 1,聚类效果最差;
  • b(i) == a(i)时,S(i) = 0,分类出现重叠。
    sklearn中提供的轮廓系数API:
score = sm.silhouette_score(x, # 样本
                            clustering_labels_, # 标签
                            sample_size=len(x), # 样本数量
                            metric="euclidean")  # 欧式距离度量

OK,简单总结就是如此。真的希望可以结识更多志同道合的朋友,一起加油,未来真的是如此精彩。。。

猜你喜欢

转载自blog.csdn.net/m0_46278903/article/details/113747322