2.3. 聚类#

可以使用 sklearn.cluster 模块对未标记数据执行聚类

每种聚类算法都有两种变体:一种是类,它实现了 fit 方法来在训练数据上学习聚类;另一种是函数,它在给定训练数据的情况下返回一个整数标签数组,对应于不同的聚类。对于类,可以在 labels_ 属性中找到训练数据上的标签。

2.3.1. 聚类方法概述#

../_images/sphx_glr_plot_cluster_comparison_001.png

scikit-learn 中聚类算法的比较#

方法名称

参数

可伸缩性

用例

几何(使用的度量)

K-Means

聚类数量

使用 MiniBatch code 的非常大的 n_samples,中等的 n_clusters

通用目的,聚类大小均匀,平面几何,聚类数量不要太多,归纳式

点之间的距离

Affinity propagation

阻尼,样本偏好

不随 n_samples 伸缩

许多聚类,聚类大小不均匀,非平面几何,归纳式

图距离(例如最近邻图)

Mean-shift

带宽

不随 n_samples 伸缩

许多聚类,聚类大小不均匀,非平面几何,归纳式

点之间的距离

Spectral clustering

聚类数量

中等的 n_samples,小的 n_clusters

少量聚类,聚类大小均匀,非平面几何,转导式

图距离(例如最近邻图)

Ward hierarchical clustering

聚类数量或距离阈值

大的 n_samplesn_clusters

许多聚类,可能有连通性约束,转导式

点之间的距离

Agglomerative clustering

聚类数量或距离阈值,连接类型,距离

大的 n_samplesn_clusters

许多聚类,可能有连通性约束,非欧几里得距离,转导式

任意成对距离

DBSCAN

邻域大小

非常大的 n_samples,中等的 n_clusters

非平面几何,聚类大小不均匀,异常值去除,转导式

最近点之间的距离

HDBSCAN

最小聚类成员数,最小点邻居数

大的 n_samples,中等的 n_clusters

非平面几何,聚类大小不均匀,异常值去除,转导式,分层,可变聚类密度

最近点之间的距离

OPTICS

最小聚类成员数

非常大的 n_samples,大的 n_clusters

非平面几何,聚类大小不均匀,可变聚类密度,异常值去除,转导式

点之间的距离

Gaussian mixtures

许多

不可伸缩

平面几何,适用于密度估计,归纳式

到中心点的马氏距离

BIRCH

分支因子,阈值,可选全局聚类器。

大的 n_clustersn_samples

大数据集,异常值去除,数据降维,归纳式

点之间的欧几里得距离

Bisecting K-Means

聚类数量

非常大的 n_samples,中等的 n_clusters

通用目的,聚类大小均匀,平面几何,无空聚类,归纳式,分层

点之间的距离

当聚类具有特定形状(即非平面流形)且标准欧几里得距离不是正确的度量标准时,非平面几何聚类非常有用。这种情况出现在上图的前两行中。

高斯混合模型(可用于聚类)在 文档的另一章 中专门介绍混合模型。KMeans 可以看作是高斯混合模型的一种特殊情况,其中每个分量的协方差相等。

转导式 聚类方法(与 归纳式 聚类方法相反)并非设计用于应用于新的、未见过的数据。

示例

  • 归纳式聚类:一个用于处理新数据的归纳式聚类模型示例。

2.3.2. K-means#

KMeans 算法通过尝试将样本分离成 n 个方差相等的组来聚类数据,同时最小化一个称为 惯性 或簇内平方和的标准(见下文)。此算法需要指定聚类的数量。它对大量样本具有良好的伸缩性,并已应用于许多不同领域的大量应用。

K-means 算法将一组 \(N\) 个样本 \(X\) 分成 \(K\) 个不相交的聚类 \(C\),每个聚类由聚类中样本的均值 \(\mu_j\) 描述。这些均值通常称为聚类“质心”;请注意,它们通常不是来自 \(X\) 的点,尽管它们位于同一空间中。

K-means 算法旨在选择使 惯性簇内平方和标准 最小的质心

\[\sum_{i=0}^{n}\min_{\mu_j \in C}(||x_i - \mu_j||^2)\]

惯性可以被认为是衡量聚类内部连贯性的一种度量。它有各种缺点

  • 惯性假设聚类是凸的且各向同性,情况并非总是如此。它对细长聚类或具有不规则形状的流形响应不佳。

  • 惯性不是一个标准化的度量:我们只知道较低的值更好,零是最佳的。但在非常高维的空间中,欧几里得距离往往会膨胀(这是所谓的“维度灾难”的一个实例)。在 k-means 聚类之前运行降维算法(例如 主成分分析 (PCA))可以缓解此问题并加快计算速度。

../_images/sphx_glr_plot_kmeans_assumptions_002.png

有关上述问题的更详细描述以及如何解决这些问题,请参阅示例 k-means 假设演示使用轮廓分析选择 KMeans 聚类中的聚类数量

K-means 通常被称为 Lloyd 算法。用基本术语来说,该算法有三个步骤。第一步选择初始质心,最基本的方法是从数据集 \(X\) 中选择 \(k\) 个样本。初始化后,K-means 包括在另外两个步骤之间循环。第一步将每个样本分配给其最近的质心。第二步通过采用分配给每个先前质心的所有样本的平均值来创建新质心。计算新旧质心之间的差异,算法重复最后两个步骤,直到此值小于阈值。换句话说,它重复直到质心不再显著移动。

../_images/sphx_glr_plot_kmeans_digits_001.png

K-means 等效于具有小、全相等、对角协方差矩阵的期望最大化算法。

该算法也可以通过 Voronoi 图 的概念来理解。首先使用当前质心计算点的 Voronoi 图。Voronoi 图中的每个段成为一个单独的聚类。其次,质心更新为每个段的均值。然后算法重复此过程直到满足停止标准。通常,当迭代之间目标函数的相对下降小于给定的容差值时,算法停止。在此实现中并非如此:当质心移动小于容差时,迭代停止。

给定足够的时间,K-means 总是会收敛,但这可能是局部最小值。这在很大程度上取决于质心的初始化。因此,计算通常会重复多次,使用不同的质心初始化。解决此问题的一种方法是 k-means++ 初始化方案,该方案已在 scikit-learn 中实现(使用 init='k-means++' 参数)。这会将质心初始化为(通常)彼此远离,从而可能比随机初始化产生更好的结果,如参考文献所示。有关比较不同初始化方案的详细示例,请参阅 手写数字数据上的 K-Means 聚类演示k-means 初始化影响的经验评估

K-means++ 也可以独立调用,以选择其他聚类算法的种子,详见 sklearn.cluster.kmeans_plusplus 和示例用法。

该算法支持样本权重,可以通过参数 sample_weight 给出。这允许在计算聚类中心和惯性值时为某些样本分配更大的权重。例如,为样本分配权重 2 等同于将该样本的副本添加到数据集 \(X\)

示例

2.3.2.1. 低级并行性#

KMeans 受益于通过 Cython 实现的基于 OpenMP 的并行性。小块数据(256 个样本)并行处理,这还产生了低内存占用。有关如何控制线程数的更多详细信息,请参阅我们的 并行性 注释。

示例

参考文献#

2.3.2.2. Mini Batch K-Means#

MiniBatchKMeansKMeans 算法的一种变体,它使用 mini-batch 来减少计算时间,同时仍尝试优化相同的目标函数。Mini-batch 是输入数据的子集,在每次训练迭代中随机采样。这些 mini-batch 大幅减少了收敛到局部解所需的计算量。与减少 k-means 收敛时间的G其他算法相比,mini-batch k-means 产生的结果通常仅比标准算法稍差。

该算法在两个主要步骤之间迭代,类似于普通的 k-means。在第一步中,从数据集中随机抽取 \(b\) 个样本,形成一个 mini-batch。然后将这些样本分配给最近的质心。在第二步中,更新质心。与 k-means 相比,这是按每个样本进行的。对于 mini-batch 中的每个样本,通过取样本和分配给该质心的所有先前样本的流式平均值来更新分配的质心。这会随着时间的推移降低质心的变化率。执行这些步骤直到收敛或达到预定的迭代次数。

MiniBatchKMeansKMeans 收敛得更快,但结果质量有所降低。在实践中,这种质量差异可能很小,如示例和引用的参考文献所示。

../_images/sphx_glr_plot_mini_batch_kmeans_001.png

示例

参考文献#

2.3.3. Affinity Propagation#

AffinityPropagation 通过在样本对之间发送消息直到收敛来创建聚类。然后使用少量范例来描述数据集,这些范例被确定为最能代表其他样本的范例。在样本对之间发送的消息表示一个样本作为另一个样本的范例的适用性,该适用性会根据来自其他对的值进行更新。这种更新会迭代发生直到收敛,此时选择最终范例,从而给出最终聚类。

../_images/sphx_glr_plot_affinity_propagation_001.png

Affinity Propagation 可能很有趣,因为它会根据提供的数据选择聚类数量。为此,两个重要参数是 preference(控制使用的范例数量)和 damping factor(衰减责任和可用性消息以避免更新这些消息时的数值振荡)。

Affinity Propagation 的主要缺点是其复杂性。该算法的时间复杂度为 \(O(N^2 T)\),其中 \(N\) 是样本数量,\(T\) 是收敛前的迭代次数。此外,如果使用密集相似性矩阵,则内存复杂度为 \(O(N^2)\),但如果使用稀疏相似性矩阵,则可以减少。这使得 Affinity Propagation 最适合中小型数据集。

算法描述#

在点之间发送的消息属于两类之一。第一类是 responsibility \(r(i, k)\),它是样本 \(k\) 应该成为样本 \(i\) 的范例的累积证据。第二类是 availability \(a(i, k)\),它是样本 \(i\) 应该选择样本 \(k\) 作为其范例的累积证据,并考虑所有其他样本的值,即 \(k\) 应该是一个范例。通过这种方式,如果范例 (1) 与许多样本足够相似并且 (2) 被许多样本选择为代表它们自己,则样本选择范例。

更正式地,样本 \(k\) 成为样本 \(i\) 的范例的 responsibility 由下式给出

\[r(i, k) \leftarrow s(i, k) - max [ a(i, k') + s(i, k') \forall k' \neq k ]\]

其中 \(s(i, k)\) 是样本 \(i\)\(k\) 之间的相似性。样本 \(k\) 成为样本 \(i\) 的范例的 availability 由下式给出

\[a(i, k) \leftarrow min [0, r(k, k) + \sum_{i'~s.t.~i' \notin \{i, k\}}{r(i', k)}]\]

首先,所有 \(r\)\(a\) 的值都设置为零,并且每次计算都会迭代直到收敛。如上所述,为了避免更新消息时的数值振荡,在迭代过程中引入了阻尼因子 \(\lambda\)

\[r_{t+1}(i, k) = \lambda\cdot r_{t}(i, k) + (1-\lambda)\cdot r_{t+1}(i, k)\]
\[a_{t+1}(i, k) = \lambda\cdot a_{t}(i, k) + (1-\lambda)\cdot a_{t+1}(i, k)\]

其中 \(t\) 表示迭代次数。

示例

2.3.4. Mean Shift#

MeanShift 聚类旨在发现平滑样本密度中的 blob。它是一种基于质心的算法,通过更新质心候选者,使其成为给定区域内点的均值来工作。然后对这些候选者进行后处理阶段过滤以消除近乎重复的项,以形成最终的质心集。

数学细节#

使用一种称为爬山的策略迭代调整质心候选者的位置,该策略查找估计概率密度的局部最大值。给定迭代 \(t\) 的候选质心 \(x\),根据以下等式更新候选者

\[x^{t+1} = x^t + m(x^t)\]

其中 \(m\)均值漂移 向量,它为每个指向点密度最大增加区域的质心计算。为了计算 \(m\),我们定义 \(N(x)\)\(x\) 周围给定距离内的样本邻域。然后使用以下等式计算 \(m\),有效地将质心更新为其邻域内样本的均值

\[m(x) = \frac{1}{|N(x)|} \sum_{x_j \in N(x)}x_j - x\]

通常,\(m\) 的等式取决于用于密度估计的核。通用公式为

\[m(x) = \frac{\sum_{x_j \in N(x)}K(x_j - x)x_j}{\sum_{x_j \in N(x)}K(x_j - x)} - x\]

在我们的实现中,如果 \(x\) 足够小,则 \(K(x)\) 等于 1,否则等于 0。实际上 \(K(y - x)\) 表示 \(y\) 是否在 \(x\) 的邻域内。

算法会自动设置聚类数量,而不是依赖于参数 bandwidth,该参数决定要搜索的区域大小。可以手动设置此参数,但可以使用提供的 estimate_bandwidth 函数进行估计,如果在未设置带宽的情况下调用该函数。

该算法的伸缩性不高,因为它在算法执行过程中需要多次最近邻搜索。算法保证收敛,但是当质心变化很小时,算法将停止迭代。

通过查找给定样本的最近质心来执行新样本的标记。

../_images/sphx_glr_plot_mean_shift_001.png

示例

参考文献#

2.3.5. Spectral clustering#

SpectralClustering 执行样本之间亲和力矩阵的低维嵌入,然后对低维空间中特征向量的分量进行聚类,例如使用 KMeans。如果亲和力矩阵稀疏且使用 amg 求解器解决特征值问题,则计算效率特别高(注意,amg 求解器要求安装 pyamg 模块)。

当前版本的 SpectralClustering 要求事先指定聚类数量。它适用于少量聚类,但不建议用于许多聚类。

对于两个聚类,SpectralClustering 解决了相似性图上的 归一化割 问题的凸松弛:将图分成两部分,使得被割边的权重与每个聚类内部边的权重相比很小。当处理图像时,此标准特别有趣,其中图顶点是像素,相似性图边的权重是使用图像梯度的函数计算的。

noisy_img segmented_img

警告

将距离转换为表现良好的相似性

请注意,如果您的相似性矩阵的值分布不佳,例如具有负值或具有距离矩阵而不是相似性,则谱问题将是奇异的且问题无法解决。在这种情况下,建议对矩阵的条目应用转换。例如,在有符号距离矩阵的情况下,通常应用热核

similarity = np.exp(-beta * distance / distance.std())

有关此类应用的示例,请参阅示例。

示例

2.3.5.1. 不同的标签分配策略#

可以使用不同的标签分配策略,对应于 SpectralClusteringassign_labels 参数。"kmeans" 策略可以匹配更精细的细节,但可能不稳定。特别是,除非您控制 random_state,否则它可能无法在每次运行中重现,因为它取决于随机初始化。替代的 "discretize" 策略是 100% 可重现的,但倾向于创建形状相当均匀和几何形状的包裹。最近添加的 "cluster_qr" 选项是一种确定性替代方案,在下面的示例应用中倾向于创建视觉上最佳的分区。

assign_labels="kmeans"

assign_labels="discretize"

assign_labels="cluster_qr"

coin_kmeans

coin_discretize

coin_cluster_qr

参考文献#

2.3.5.2. 谱聚类图#

谱聚类也可以用于通过其谱嵌入来划分图。在这种情况下,亲和力矩阵是图的邻接矩阵,并且 SpectralClustering 使用 affinity='precomputed' 初始化

>>> from sklearn.cluster import SpectralClustering
>>> sc = SpectralClustering(3, affinity='precomputed', n_init=100,
...                         assign_labels='discretize')
>>> sc.fit_predict(adjacency_matrix)
参考文献#

2.3.6. 分层聚类#

分层聚类是一类通用的聚类算法,它通过连续合并或拆分聚类来构建嵌套聚类。这种聚类层次结构表示为一棵树(或树状图)。树的根是包含所有样本的唯一聚类,叶子是仅包含一个样本的聚类。有关更多详细信息,请参阅 Wikipedia 页面

AgglomerativeClustering 对象使用自下而上的方法执行分层聚类:每个观测值都从自己的聚类开始,然后聚类依次合并在一起。连接准则决定了用于合并策略的度量标准

  • Ward 最小化所有聚类内的平方差之和。它是一种方差最小化方法,从这个意义上讲类似于 k-means 目标函数,但采用了一种凝聚分层方法。

  • Maximumcomplete linkage 最小化聚类对之间观测值的最大距离。

  • Average linkage 最小化聚类对之间所有观测值距离的平均值。

  • Single linkage 最小化聚类对之间最近观测值之间的距离。

AgglomerativeClustering 与连通性矩阵一起使用时,它也可以扩展到大量样本,但在样本之间没有添加连通性约束时计算成本很高:它在每个步骤都考虑所有可能的合并。

2.3.6.1. 不同的连接类型:Ward、complete、average 和 single linkage#

AgglomerativeClustering 支持 Ward、single、average 和 complete linkage 策略。

../_images/sphx_glr_plot_linkage_comparison_001.png

凝聚聚类具有“富者愈富”的行为,导致聚类大小不均匀。在这方面,single linkage 是最差的策略,而 Ward 给出了最规则的大小。然而,Ward 不能改变亲和力(或用于聚类的距离),因此对于非欧几里得度量,average linkage 是一个很好的替代方案。Single linkage 虽然对嘈杂数据不稳健,但可以非常有效地计算,因此可用于提供对更大数据集的分层聚类。Single linkage 在非球形数据上也可以表现良好。

示例

2.3.6.2. 聚类层次结构可视化#

可以将表示聚类分层合并的树可视化为树状图。视觉检查通常有助于理解数据结构,尽管对于小样本量更是如此。

../_images/sphx_glr_plot_agglomerative_dendrogram_001.png

示例

2.3.6.3. 添加连通性约束#

AgglomerativeClustering 的一个有趣方面是,可以向此算法添加连通性约束(只有相邻的聚类才能合并在一起),通过一个连通性矩阵来定义每个样本的邻近样本,该矩阵遵循给定的数据结构。例如,在下面的 Swiss-roll 示例中,连通性约束禁止合并在 Swiss roll 上不相邻的点,从而避免形成延伸到卷重叠折叠上的聚类。

unstructured structured

这些约束不仅有助于施加一定的局部结构,而且还可以使算法更快,特别是当样本数量很高时。

连通性约束是通过连通性矩阵施加的:一个 scipy 稀疏矩阵,其元素仅位于应连接的数据集索引的行和列的交集处。此矩阵可以从先验信息构建:例如,您可能希望通过仅合并具有从一个页面指向另一个页面的链接的页面来聚类网页。它也可以从数据中学习,例如使用 sklearn.neighbors.kneighbors_graph 将合并限制为最近邻,如 本示例 所示,或者使用 sklearn.feature_extraction.image.grid_to_graph 只允许合并图像上的相邻像素,如 硬币 示例所示。

警告

具有 single、average 和 complete linkage 的连通性约束

连通性约束和 single、complete 或 average linkage 可以增强凝聚聚类“富者愈富”的方面,特别是如果它们是使用 sklearn.neighbors.kneighbors_graph 构建的。在聚类数量很少的限制下,它们倾向于给出一些宏观上被占用的聚类和几乎为空的聚类。(请参阅 具有和不具有结构的分层聚类 中的讨论)。Single linkage 是关于此问题的最脆弱的连接选项。

../_images/sphx_glr_plot_ward_structured_vs_unstructured_003.png

示例

2.3.6.4. 改变度量#

Single、average 和 complete linkage 可以与各种距离(或亲和力)一起使用,特别是欧几里得距离(l2)、曼哈顿距离(或 Cityblock,或 l1)、余弦距离,或任何预先计算的亲和力矩阵。

  • l1 距离通常适用于稀疏特征或稀疏噪声:即许多特征为零,例如在使用稀有词出现次数进行文本挖掘时。

  • cosine 距离很有趣,因为它不受信号全局缩放的影响。

选择度量的指导原则是使用一个使不同类中的样本之间距离最大化,并使每个类内的距离最小化的度量。

../_images/sphx_glr_plot_agglomerative_clustering_metrics_005.png ../_images/sphx_glr_plot_agglomerative_clustering_metrics_006.png ../_images/sphx_glr_plot_agglomerative_clustering_metrics_007.png

示例

2.3.6.5. Bisecting K-Means#

BisectingKMeansKMeans 的迭代变体,使用分裂分层聚类。它不是一次创建所有质心,而是根据先前的聚类逐步选择质心:一个聚类被重复分成两个新聚类,直到达到目标聚类数量。

当聚类数量很大时,BisectingKMeansKMeans 更高效,因为它在每次二分时只处理数据的一个子集,而 KMeans 总是处理整个数据集。

尽管 BisectingKMeans 无法从设计上的 "k-means++" 初始化的优势中受益,但它仍将产生与 KMeans(init="k-means++") 可比的结果(在惯性方面),而计算成本更低,并且可能比随机初始化的 KMeans 产生更好的结果。

如果聚类数量相对于数据点数量较少,则此变体比凝聚聚类更高效。

此变体也不会产生空聚类。

存在两种选择要拆分的聚类的策略
  • bisecting_strategy="largest_cluster" 选择包含最多点的聚类

  • bisecting_strategy="biggest_inertia" 选择具有最大惯性的聚类(簇内平方和最大的聚类)

在大多数情况下,按最大数据点数量选择会产生与按惯性选择一样准确的结果,并且速度更快(特别是对于大量数据点,计算误差可能成本很高)。

按最大数据点数量选择也可能产生大小相似的聚类,而 KMeans 以产生大小不同的聚类而闻名。

Bisecting K-Means 和常规 K-Means 之间的差异可以在示例 Bisecting K-Means 和常规 K-Means 性能比较 中看到。虽然常规 K-Means 算法倾向于创建不相关的聚类,但 Bisecting K-Means 的聚类顺序良好,并创建了相当可见的层次结构。

参考文献#

2.3.7. DBSCAN#

DBSCAN 算法将聚类视为被低密度区域分隔的高密度区域。由于这种相当通用的视图,DBSCAN 发现的聚类可以是任何形状,这与假设聚类为凸形的 k-means 不同。DBSCAN 的核心组件是 核心样本 的概念,核心样本是位于高密度区域的样本。因此,一个聚类是一组核心样本(彼此接近,通过某种距离度量来衡量)和一组非核心样本(接近核心样本,但本身不是核心样本)。算法有两个参数,min_sampleseps,它们正式定义了我们所说的 密集 的含义。更高的 min_samples 或更低的 eps 表示形成聚类所需的密度更高。

更正式地,我们将核心样本定义为数据集中的一个样本,使得在距离 eps 内存在 min_samples 个其他样本,这些样本被定义为核心样本的 邻居。这告诉我们核心样本位于向量空间的密集区域。一个聚类是一组核心样本,可以通过递归地取一个核心样本,找到所有作为核心样本的邻居,找到 它们 的所有作为核心样本的邻居,依此类推来构建。一个聚类还具有一组非核心样本,这些样本是聚类中核心样本的邻居,但本身不是核心样本。直观地说,这些样本位于聚类的边缘。

根据定义,任何核心样本都是聚类的一部分。任何非核心样本,且距离任何核心样本至少 eps 的距离,都被算法视为异常值。

虽然参数 min_samples 主要控制算法对噪声的容忍度(在嘈杂和大数据集上可能需要增加此参数),但参数 eps 对于数据集和距离函数 至关重要,通常不能保留默认值。它控制点的局部邻域。当选择得太小时,大多数数据根本不会被聚类(并标记为 -1 表示“噪声”)。当选择得太大时,它会导致相近的聚类合并为一个聚类,最终整个数据集被作为单个聚类返回。文献中讨论了一些选择此参数的启发式方法,例如基于最近邻距离图中的拐点(如下面参考文献所述)。

在下图中,颜色表示聚类成员身份,大圆圈表示算法发现的核心样本。小圆圈是非核心样本,但仍是聚类的一部分。此外,异常值由下面的黑点表示。

dbscan_results

示例

实现#

DBSCAN 算法是确定性的,当给定相同数据以相同顺序时,总是生成相同的聚类。然而,当数据以不同顺序提供时,结果可能会有所不同。首先,尽管核心样本总是被分配到相同的聚类,但这些聚类的标签将取决于数据中遇到这些样本的顺序。其次,更重要的是,非核心样本被分配到的聚类可能会根据数据顺序而有所不同。当一个非核心样本与不同聚类中的两个核心样本的距离小于 eps 时,就会发生这种情况。根据三角不等式,这两个核心样本之间的距离必须大于 eps,否则它们将位于同一聚类中。非核心样本被分配给在遍历数据时首先生成的聚类,因此结果将取决于数据排序。

当前的实现使用球树和 kd 树来确定点的邻域,这避免了计算完整的距离矩阵(如在 scikit-learn 0.14 版本之前所做的那样)。保留了使用自定义度量的可能性;有关详细信息,请参阅 NearestNeighbors

大样本量下的内存消耗#

此实现默认情况下不是内存高效的,因为它在无法使用 kd 树或球树的情况下(例如,使用稀疏矩阵)会构建一个完整的成对相似性矩阵。此矩阵将消耗 \(n^2\) 个浮点数。解决此问题的几种机制是

  • 结合 extract_dbscan 方法使用 OPTICS 聚类。OPTICS 聚类也会计算完整的成对矩阵,但一次只在内存中保留一行(内存复杂度 \(\mathcal{O}(n)\))。

  • 可以以内存高效的方式预先计算稀疏半径邻域图(其中缺失的条目被假定为超出 eps),然后使用 metric='precomputed' 在其上运行 dbscan。请参阅 sklearn.neighbors.NearestNeighbors.radius_neighbors_graph

  • 可以压缩数据集,方法是删除数据中出现的精确重复项,或者使用 BIRCH。然后,您只需要相对少量代表大量点。然后可以在拟合 DBSCAN 时提供 sample_weight

参考文献#

2.3.8. HDBSCAN#

HDBSCAN 算法可以看作是 DBSCANOPTICS 的扩展。具体来说,DBSCAN 假设聚类标准(即密度要求)是 全局同质 的。换句话说,DBSCAN 可能难以成功捕获具有不同密度的聚类。HDBSCAN 缓解了这一假设,并通过构建聚类问题的替代表示来探索所有可能的密度尺度。

注意

此实现改编自 HDBSCAN 的原始实现,scikit-learn-contrib/hdbscan 基于 [LJ2017]

示例

2.3.8.1. 相互可达性图#

HDBSCAN 首先将样本 \(x_p\)核心距离 \(d_c(x_p)\) 定义为其第 min_samples 个最近邻居的距离(包括自身)。例如,如果 min_samples=5\(x_*\)\(x_p\) 的第 5 个最近邻居,则核心距离为

\[d_c(x_p)=d(x_p, x_*).\]

接下来,它将两个点 \(x_p, x_q\)相互可达性距离 \(d_m(x_p, x_q)\) 定义为

\[d_m(x_p, x_q) = \max\{d_c(x_p), d_c(x_q), d(x_p, x_q)\}\]

这两个概念允许我们构建 相互可达性图 \(G_{ms}\),该图通过将每个样本 \(x_p\) 与图的顶点相关联来定义,从而点 \(x_p, x_q\) 之间的边是它们之间的相互可达性距离 \(d_m(x_p, x_q)\)。我们可以通过移除值大于 \(\varepsilon\) 的任何边来构建此图的子集,表示为 \(G_{ms,\varepsilon}\):从原始图。在此阶段,核心距离小于 \(\varepsilon\) 的任何点都被标记为噪声。然后通过找到此修剪图的连接分量来聚类剩余的点。

注意

获取修剪图 \(G_{ms,\varepsilon}\) 的连通分量等同于运行 DBSCAN*,其中包含 min_samples\(\varepsilon\)。DBSCAN* 是 [CM2013] 中提到的 DBSCAN 的略微修改版本。

2.3.8.2. 层次聚类#

HDBSCAN 可以被视为一种算法,它对所有 \(\varepsilon\) 值执行 DBSCAN* 聚类。如前所述,这等同于为所有 \(\varepsilon\) 值找到互达图的连通分量。为了高效地实现这一点,HDBSCAN 首先从完全连接的互达图(mutual reachability graph)中提取最小生成树(MST),然后贪婪地切除权重最高的边。HDBSCAN 算法的概要如下:

  1. 提取 \(G_{ms}\) 的 MST。

  2. 通过为每个顶点添加一个“自循环边”(self edge)来扩展 MST,该边的权重等于底层样本的核心距离。

  3. 为 MST 初始化一个单一聚类和标签。

  4. 从 MST 中移除权重最大的边(同时移除权重相同的边)。

  5. 将聚类标签分配给包含现在移除的边端点的连通分量。如果分量不包含至少一条边,则将其分配一个“空”标签,标记为噪声。

  6. 重复步骤 4-5,直到不再有连通分量。

因此,HDBSCAN 能够以层次方式获取 DBSCAN* 在固定 min_samples 选择下可实现的所有可能分区。事实上,这使得 HDBSCAN 能够跨多种密度执行聚类,因此它不再需要将 \(\varepsilon\) 作为超参数给出。相反,它仅依赖于 min_samples 的选择,这往往是一个更健壮的超参数。

hdbscan_ground_truth

hdbscan_results

HDBSCAN 可以通过附加超参数 min_cluster_size 进行平滑处理,该参数指定在层次聚类期间,样本数量少于 minimum_cluster_size 的分量被视为噪声。在实践中,可以将 minimum_cluster_size = min_samples 来耦合参数并简化超参数空间。

References

[CM2013]

Campello, R.J.G.B., Moulavi, D., Sander, J. (2013). Density-Based Clustering Based on Hierarchical Density Estimates. In: Pei, J., Tseng, V.S., Cao, L., Motoda, H., Xu, G. (eds) Advances in Knowledge Discovery and Data Mining. PAKDD 2013. Lecture Notes in Computer Science(), vol 7819. Springer, Berlin, Heidelberg. Density-Based Clustering Based on Hierarchical Density Estimates

[LJ2017]

L. McInnes and J. Healy, (2017). Accelerated Hierarchical Density Based Clustering. In: IEEE International Conference on Data Mining Workshops (ICDMW), 2017, pp. 33-42. Accelerated Hierarchical Density Based Clustering

2.3.9. OPTICS#

OPTICS 算法与 DBSCAN 算法有许多相似之处,可以被认为是 DBSCAN 的一种推广,它将 eps 要求从单个值放宽到值范围。DBSCAN 和 OPTICS 之间的主要区别在于 OPTICS 算法构建了一个*可达性*图(reachability graph),它为每个样本分配了一个 reachability_ 距离,以及在聚类 ordering_ 属性中的位置;这两个属性在模型拟合时被分配,并用于确定聚类成员资格。如果 OPTICS 运行时 max_eps 设置为默认值 inf,那么可以使用 cluster_optics_dbscan 方法以线性时间对任何给定的 eps 值重复执行 DBSCAN 式的聚类提取。将 max_eps 设置为较低的值将导致更短的运行时间,可以将其视为从每个点查找其他潜在可达点的最大邻域半径。

optics_results

OPTICS 生成的*可达性*距离允许在单个数据集中提取可变密度的聚类。如上图所示,结合*可达性*距离和数据集 ordering_ 会生成一个*可达性图*,其中点密度在 Y 轴上表示,点被排序以便相邻点相邻。在单个值处“切割”可达性图会产生类似 DBSCAN 的结果;“切割”上方的所有点都被归类为噪声,并且每次从左到右读取时出现中断都表示一个新的聚类。OPTICS 的默认聚类提取着眼于图中的陡峭斜率来寻找聚类,用户可以使用参数 xi 定义什么是陡峭斜率。图本身还有其他分析可能性,例如通过可达性图树状图生成数据的层次表示,并且可以通过 cluster_hierarchy_ 参数访问算法检测到的聚类层次结构。上图已进行颜色编码,以便平面空间中的聚类颜色与可达性图的线性分段聚类相匹配。请注意,蓝色和红色聚类在可达性图中是相邻的,并且可以在层次结构上表示为更大父聚类的子聚类。

示例

与 DBSCAN 的比较#

OPTICS cluster_optics_dbscan 方法和 DBSCAN 的结果非常相似,但并非总是完全相同;特别是周边点和噪声点的标记。这部分是因为 OPTICS 处理的每个密集区域的第一个样本具有较大的可达性值,同时又靠近其区域中的其他点,因此有时会被标记为噪声而不是周边。这会影响相邻点在被考虑标记为周边或噪声时的判断。

请注意,对于任何单个 eps 值,DBSCAN 的运行时间往往比 OPTICS 短;但是,对于在不同 eps 值下重复运行,OPTICS 的单次运行可能需要更少的累积运行时间。同样重要的是要注意,只有当 epsmax_eps 接近时,OPTICS 的输出才接近 DBSCAN。

计算复杂度#

使用空间索引树来避免计算完整的距离矩阵,并允许在大型样本集上高效利用内存。可以通过 metric 关键字提供不同的距离度量。

对于大型数据集,可以通过 HDBSCAN 获得相似(但不完全相同)的结果。HDBSCAN 实现是多线程的,并且具有比 OPTICS 更好的算法运行时间复杂度,但代价是更差的内存扩展性。对于使用 HDBSCAN 会耗尽系统内存的超大型数据集,OPTICS 将保持 \(n\)(而不是 \(n^2\))的内存扩展性;但是,可能需要调整 max_eps 参数才能在合理的时间内获得解决方案。

参考文献#
  • “OPTICS: ordering points to identify the clustering structure.” Ankerst, Mihael, Markus M. Breunig, Hans-Peter Kriegel, and Jörg Sander. In ACM Sigmod Record, vol. 28, no. 2, pp. 49-60. ACM, 1999.

2.3.10. BIRCH#

Birch 为给定数据构建了一棵名为聚类特征树(Clustering Feature Tree,CFT)的树。数据被有损压缩为一组聚类特征节点(CF Nodes)。CF 节点包含许多子聚类,称为聚类特征子聚类(CF Subclusters),位于非终端 CF 节点中的这些 CF 子聚类可以有 CF 节点作为子节点。

CF 子聚类保留了聚类所需的信息,从而避免了将整个输入数据保存在内存中的需要。这些信息包括:

  • 子聚类中的样本数量。

  • 线性求和 - 一个包含所有样本总和的 n 维向量。

  • 平方求和 - 所有样本平方 L2 范数的总和。

  • 质心 - 避免重新计算线性求和 / n_samples。

  • 质心的平方范数。

BIRCH 算法有两个参数:阈值(threshold)和分支因子(branching factor)。分支因子限制了一个节点中的子聚类数量,阈值限制了进入样本与现有子聚类之间的距离。

该算法可以被视为一种数据缩减方法,因为它将输入数据缩减为一组直接从 CFT 叶子中获取的子聚类。这些缩减后的数据可以通过将其输入到全局聚类器中进一步处理。该全局聚类器可以通过 n_clusters 设置。如果 n_clusters 设置为 None,则直接读取叶子中的子聚类;否则,全局聚类步骤会将这些子聚类标记为全局聚类(标签),并将样本映射到最近子聚类的全局标签。

算法描述#
  • 一个新样本被插入到 CF 树的根节点(这是一个 CF 节点)。然后它与根节点中合并后半径最小的子聚类合并,受阈值和分支因子条件的约束。如果子聚类有任何子节点,则重复此操作直到到达叶子。在叶子中找到最近的子聚类后,递归更新该子聚类和父子聚类的属性。

  • 如果合并新样本和最近子聚类后获得的子聚类半径大于阈值的平方,并且子聚类的数量大于分支因子,则为该新样本临时分配一个空间。选择两个最远的子聚类,并根据这些子聚类之间的距离将子聚类分为两组。

  • 如果这个拆分的节点有一个父子聚类并且有空间容纳一个新的子聚类,那么父节点被拆分为两个。如果没有空间,则这个节点再次拆分为两个,并且该过程递归进行,直到到达根节点。

BIRCH 还是 MiniBatchKMeans?#
  • BIRCH 在高维数据上的扩展性不是很好。经验法则是,如果 n_features 大于二十,通常最好使用 MiniBatchKMeans。

  • 如果需要减少数据实例的数量,或者如果想要大量子聚类(无论是作为预处理步骤还是其他方式),BIRCH 比 MiniBatchKMeans 更有用。

../_images/sphx_glr_plot_birch_vs_minibatchkmeans_001.png
如何使用 partial_fit?#

为了避免全局聚类计算,对于每次调用 partial_fit,建议用户:

  1. 最初设置 n_clusters=None

  2. 通过多次调用 partial_fit 训练所有数据。

  3. 使用 brc.set_params(n_clusters=n_clusters)n_clusters 设置为所需值。

  4. 最后调用不带参数的 partial_fit,即 brc.partial_fit(),它执行全局聚类。

参考文献#

2.3.11. 聚类性能评估#

评估聚类算法的性能不像计算错误数量或监督分类算法的精度和召回率那样简单。特别是,任何评估指标都不应考虑聚类标签的绝对值,而应考虑聚类是否定义了与某些基本事实类别集相似的数据分离,或者是否满足某些假设,例如根据某个相似性度量,属于同一类别的成员比属于不同类别的成员更相似。

2.3.11.1. 兰德指数#

给定基本事实类别分配 labels_true 以及我们对相同样本的聚类算法分配 labels_pred(调整或未调整的)兰德指数是一个衡量两种分配相似性的函数,忽略排列。

>>> from sklearn import metrics
>>> labels_true = [0, 0, 0, 1, 1, 1]
>>> labels_pred = [0, 0, 1, 1, 2, 2]
>>> metrics.rand_score(labels_true, labels_pred)
0.66

兰德指数不保证随机标签的得分接近 0.0。调整兰德指数针对偶然性进行校正,并将给出这样的基准。

>>> metrics.adjusted_rand_score(labels_true, labels_pred)
0.24

与所有聚类指标一样,可以对预测标签中的 0 和 1 进行排列,将 2 重命名为 3,并获得相同的分数。

>>> labels_pred = [1, 1, 0, 0, 3, 3]
>>> metrics.rand_score(labels_true, labels_pred)
0.66
>>> metrics.adjusted_rand_score(labels_true, labels_pred)
0.24

此外,rand_scoreadjusted_rand_score 都是对称的:交换参数不会改变分数。因此,它们可以用作一致性度量

>>> metrics.rand_score(labels_pred, labels_true)
0.66
>>> metrics.adjusted_rand_score(labels_pred, labels_true)
0.24

完美标签的得分为 1.0。

>>> labels_pred = labels_true[:]
>>> metrics.rand_score(labels_true, labels_pred)
1.0
>>> metrics.adjusted_rand_score(labels_true, labels_pred)
1.0

不一致的标签(例如独立标签)得分较低,对于调整兰德指数,得分将为负或接近零。然而,对于未调整的兰德指数,得分虽然较低,但不一定接近零。

>>> labels_true = [0, 0, 0, 0, 0, 0, 1, 1]
>>> labels_pred = [0, 1, 2, 3, 4, 5, 5, 6]
>>> metrics.rand_score(labels_true, labels_pred)
0.39
>>> metrics.adjusted_rand_score(labels_true, labels_pred)
-0.072

示例

数学公式#

如果 C 是基本事实类别分配,K 是聚类,让我们定义 \(a\)\(b\) 如下:

  • \(a\),在 C 和 K 中属于同一集合的元素对数量。

  • \(b\),在 C 和 K 中属于不同集合的元素对数量。

未调整的兰德指数由下式给出:

\[\text{RI} = \frac{a + b}{C_2^{n_{samples}}}\]

其中 \(C_2^{n_{samples}}\) 是数据集中所有可能的对的总数。只要计算一致地执行,无论是对有序对还是无序对进行计算都无关紧要。

然而,兰德指数不保证随机标签分配将获得接近零的值(特别是如果聚类数量与样本数量在同一数量级)。

为了抵消这种影响,我们可以通过定义调整兰德指数如下来折算随机标签的预期 RI \(E[\text{RI}]\)

\[\text{ARI} = \frac{\text{RI} - E[\text{RI}]}{\max(\text{RI}) - E[\text{RI}]}\]
参考文献#

2.3.11.2. 基于互信息的得分#

给定基本事实类别分配 labels_true 以及我们对相同样本的聚类算法分配 labels_pred互信息是一个衡量两种分配一致性的函数,忽略排列。该度量有两个不同的归一化版本可用,即归一化互信息 (NMI)调整互信息 (AMI)。NMI 在文献中经常使用,而 AMI 是最近提出的,并且针对偶然性进行了归一化

>>> from sklearn import metrics
>>> labels_true = [0, 0, 0, 1, 1, 1]
>>> labels_pred = [0, 0, 1, 1, 2, 2]

>>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)
0.22504

可以对预测标签中的 0 和 1 进行排列,将 2 重命名为 3,并获得相同的分数。

>>> labels_pred = [1, 1, 0, 0, 3, 3]
>>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)
0.22504

所有 mutual_info_scoreadjusted_mutual_info_scorenormalized_mutual_info_score 都是对称的:交换参数不会改变分数。因此,它们可以用作一致性度量

>>> metrics.adjusted_mutual_info_score(labels_pred, labels_true)
0.22504

完美标签的得分为 1.0。

>>> labels_pred = labels_true[:]
>>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)
1.0

>>> metrics.normalized_mutual_info_score(labels_true, labels_pred)
1.0

这对于 mutual_info_score 来说不成立,因此更难判断。

>>> metrics.mutual_info_score(labels_true, labels_pred)
0.69

差的(例如独立标签)得分非正。

>>> labels_true = [0, 1, 2, 0, 3, 4, 5, 1]
>>> labels_pred = [1, 1, 0, 0, 2, 2, 2, 2]
>>> metrics.adjusted_mutual_info_score(labels_true, labels_pred)
-0.10526

示例

数学公式#

假设两个标签分配(针对相同的 N 个对象),\(U\)\(V\)。它们的熵是分区集的不确定性量,定义为:

\[H(U) = - \sum_{i=1}^{|U|}P(i)\log(P(i))\]

其中 \(P(i) = |U_i| / N\) 是从 \(U\) 中随机挑选的对象落入类别 \(U_i\) 的概率。对于 \(V\) 同样:

\[H(V) = - \sum_{j=1}^{|V|}P'(j)\log(P'(j))\]

其中 \(P'(j) = |V_j| / N\)\(U\)\(V\) 之间的互信息 (MI) 计算如下:

\[\text{MI}(U, V) = \sum_{i=1}^{|U|}\sum_{j=1}^{|V|}P(i, j)\log\left(\frac{P(i,j)}{P(i)P'(j)}\right)\]

其中 \(P(i, j) = |U_i \cap V_j| / N\) 是随机挑选的对象同时落入类别 \(U_i\)\(V_j\) 的概率。

它也可以用集合基数公式表示:

\[\text{MI}(U, V) = \sum_{i=1}^{|U|} \sum_{j=1}^{|V|} \frac{|U_i \cap V_j|}{N}\log\left(\frac{N|U_i \cap V_j|}{|U_i||V_j|}\right)\]

归一化互信息定义为:

\[\text{NMI}(U, V) = \frac{\text{MI}(U, V)}{\text{mean}(H(U), H(V))}\]

互信息和归一化变体的值未针对偶然性进行调整,并且会随着不同标签(聚类)数量的增加而增加,而与标签分配之间实际的“互信息”量无关。

可以使用以下公式计算互信息的预期值 [VEB2009]。在此公式中,\(a_i = |U_i|\)\(U_i\) 中的元素数量)和 \(b_j = |V_j|\)\(V_j\) 中的元素数量)。

\[E[\text{MI}(U,V)]=\sum_{i=1}^{|U|} \sum_{j=1}^{|V|} \sum_{n_{ij}=(a_i+b_j-N)^+ }^{\min(a_i, b_j)} \frac{n_{ij}}{N}\log \left( \frac{ N.n_{ij}}{a_i b_j}\right) \frac{a_i!b_j!(N-a_i)!(N-b_j)!}{N!n_{ij}!(a_i-n_{ij})!(b_j-n_{ij})! (N-a_i-b_j+n_{ij})!}\]

使用预期值,调整互信息可以使用与调整兰德指数相似的形式进行计算:

\[\text{AMI} = \frac{\text{MI} - E[\text{MI}]}{\text{mean}(H(U), H(V)) - E[\text{MI}]}\]

对于归一化互信息和调整互信息,归一化值通常是每个聚类熵的某个*广义*平均值。存在各种广义平均值,并且没有确定的规则来偏好其中一个。这个决定很大程度上取决于具体领域;例如,在社区检测中,算术平均值是最常见的。每种归一化方法都提供“定性相似的行为” [YAT2016]。在我们的实现中,这由 average_method 参数控制。

Vinh 等人 (2010) 根据其平均方法命名了 NMI 和 AMI 的变体 [VEB2010]。他们的“sqrt”和“sum”平均值是几何平均值和算术平均值;我们使用这些更广泛的常用名称。

References

[VEB2009]

Vinh, Epps, and Bailey, (2009). “Information theoretic measures for clusterings comparison”. Proceedings of the 26th Annual International Conference on Machine Learning - ICML ‘09. doi:10.1145/1553374.1553511. ISBN 9781605585161.

[VEB2010]

Vinh, Epps, and Bailey, (2010). “Information Theoretic Measures for Clusterings Comparison: Variants, Properties, Normalization and Correction for Chance”. JMLR <https://jmlr.csail.mit.edu/papers/volume11/vinh10a/vinh10a.pdf>

[YAT2016]

Yang, Algesheimer, and Tessone, (2016). “A comparative analysis of community detection algorithms on artificial networks”. Scientific Reports 6: 30750. doi:10.1038/srep30750.

2.3.11.3. 同质性、完整性和 V-measure#

给定样本的基本事实类别分配知识,可以使用条件熵分析定义一些直观的指标。

特别是 Rosenberg 和 Hirschberg (2007) 为任何聚类分配定义了以下两个理想目标:

  • 同质性:每个聚类只包含单个类别的成员。

  • 完整性:给定类别的所有成员都被分配到同一个聚类。

我们可以将这些概念转化为分数 homogeneity_scorecompleteness_score。两者都以 0.0 为下限,1.0 为上限(越高越好)。

>>> from sklearn import metrics
>>> labels_true = [0, 0, 0, 1, 1, 1]
>>> labels_pred = [0, 0, 1, 1, 2, 2]

>>> metrics.homogeneity_score(labels_true, labels_pred)
0.66

>>> metrics.completeness_score(labels_true, labels_pred)
0.42

它们的调和平均值称为 V-measure,由 v_measure_score 计算。

>>> metrics.v_measure_score(labels_true, labels_pred)
0.516

此函数的公式如下:

\[v = \frac{(1 + \beta) \times \text{homogeneity} \times \text{completeness}}{(\beta \times \text{homogeneity} + \text{completeness})}\]

beta 默认为 1.0,但对于使用小于 1 的 beta 值

>>> metrics.v_measure_score(labels_true, labels_pred, beta=0.6)
0.547

会更看重同质性,而使用大于 1 的值

>>> metrics.v_measure_score(labels_true, labels_pred, beta=1.8)
0.48

会更看重完整性。

V-measure 实际上等同于上面讨论的互信息 (NMI),其中聚合函数是算术平均值 [B2011]

同质性、完整性和 V-measure 可以使用 homogeneity_completeness_v_measure 一次性计算,如下所示:

>>> metrics.homogeneity_completeness_v_measure(labels_true, labels_pred)
(0.67, 0.42, 0.52)

以下聚类分配稍好一些,因为它具有同质性但不完整:

>>> labels_pred = [0, 0, 0, 1, 2, 2]
>>> metrics.homogeneity_completeness_v_measure(labels_true, labels_pred)
(1.0, 0.68, 0.81)

注意

v_measure_score对称的:它可用于评估同一数据集上两个独立分配的一致性

这对于 completeness_scorehomogeneity_score 则不然:两者都受以下关系约束:

homogeneity_score(a, b) == completeness_score(b, a)

示例

数学公式#

同质性和完整性分数形式上由下式给出:

\[h = 1 - \frac{H(C|K)}{H(C)}\]
\[c = 1 - \frac{H(K|C)}{H(K)}\]

其中 \(H(C|K)\)给定聚类分配的类别的条件熵,由下式给出:

\[H(C|K) = - \sum_{c=1}^{|C|} \sum_{k=1}^{|K|} \frac{n_{c,k}}{n} \cdot \log\left(\frac{n_{c,k}}{n_k}\right)\]

\(H(C)\)类别的熵,由下式给出:

\[H(C) = - \sum_{c=1}^{|C|} \frac{n_c}{n} \cdot \log\left(\frac{n_c}{n}\right)\]

其中 \(n\) 是样本总数,\(n_c\)\(n_k\) 分别是属于类别 \(c\) 和聚类 \(k\) 的样本数量,最后 \(n_{c,k}\) 是从类别 \(c\) 分配到聚类 \(k\) 的样本数量。

给定类别的聚类条件熵 \(H(K|C)\)聚类熵 \(H(K)\) 以对称方式定义。

Rosenberg 和 Hirschberg 进一步将 V-measure 定义为同质性和完整性的调和平均值

\[v = 2 \cdot \frac{h \cdot c}{h + c}\]

References

2.3.11.4. Fowlkes-Mallows 分数#

最初的 Fowlkes-Mallows 指数 (FMI) 旨在衡量两个聚类结果之间的相似性,这本质上是一种无监督比较。Fowlkes-Mallows 指数的监督适应版本(如 sklearn.metrics.fowlkes_mallows_score 中实现)可在已知样本的基本事实类别分配时使用。FMI 被定义为成对精度和召回率的几何平均值:

\[\text{FMI} = \frac{\text{TP}}{\sqrt{(\text{TP} + \text{FP}) (\text{TP} + \text{FN})}}\]

在上面的公式中:

  • TP (真阳性):在真实标签和预测标签中都聚在一起的点对数量。

  • FP (假阳性):在预测标签中聚在一起但在真实标签中没有聚在一起的点对数量。

  • FN (假阴性):在真实标签中聚在一起但在预测标签中没有聚在一起的点对数量。

分数范围从 0 到 1。高值表示两个聚类之间有很好的相似性。

>>> from sklearn import metrics
>>> labels_true = [0, 0, 0, 1, 1, 1]
>>> labels_pred = [0, 0, 1, 1, 2, 2]
>>> metrics.fowlkes_mallows_score(labels_true, labels_pred)
0.47140

可以对预测标签中的 0 和 1 进行排列,将 2 重命名为 3,并获得相同的分数。

>>> labels_pred = [1, 1, 0, 0, 3, 3]

>>> metrics.fowlkes_mallows_score(labels_true, labels_pred)
0.47140

完美标签的得分为 1.0。

>>> labels_pred = labels_true[:]
>>> metrics.fowlkes_mallows_score(labels_true, labels_pred)
1.0

差的(例如独立标签)得分零。

>>> labels_true = [0, 1, 2, 0, 3, 4, 5, 1]
>>> labels_pred = [1, 1, 0, 0, 2, 2, 2, 2]
>>> metrics.fowlkes_mallows_score(labels_true, labels_pred)
0.0
参考文献#

2.3.11.5. 轮廓系数#

如果不知道基本事实标签,则必须使用模型本身进行评估。轮廓系数(sklearn.metrics.silhouette_score)就是这种评估的一个例子,其中较高的轮廓系数分数对应于具有更好定义的聚类的模型。轮廓系数为每个样本定义,由两个分数组成:

  • a:样本与同一类别中所有其他点之间的平均距离。

  • b:样本与*下一个最近聚类*中所有其他点之间的平均距离。

单个样本的轮廓系数 s 由下式给出:

\[s = \frac{b - a}{max(a, b)}\]

一组样本的轮廓系数被定义为每个样本的轮廓系数的平均值。

>>> from sklearn import metrics
>>> from sklearn.metrics import pairwise_distances
>>> from sklearn import datasets
>>> X, y = datasets.load_iris(return_X_y=True)

在正常使用中,轮廓系数应用于聚类分析的结果。

>>> import numpy as np
>>> from sklearn.cluster import KMeans
>>> kmeans_model = KMeans(n_clusters=3, random_state=1).fit(X)
>>> labels = kmeans_model.labels_
>>> metrics.silhouette_score(X, labels, metric='euclidean')
0.55

示例

参考文献#

2.3.11.6. Calinski-Harabasz 指数#

如果不知道基本事实标签,可以使用 Calinski-Harabasz 指数(sklearn.metrics.calinski_harabasz_score)(也称为方差比标准)来评估模型,其中较高的 Calinski-Harabasz 分数对应于具有更好定义的聚类的模型。

该指数是所有聚类之间的离散度和聚类内部离散度之和的比率(其中离散度定义为距离平方和)。

>>> from sklearn import metrics
>>> from sklearn.metrics import pairwise_distances
>>> from sklearn import datasets
>>> X, y = datasets.load_iris(return_X_y=True)

在正常使用中,Calinski-Harabasz 指数应用于聚类分析的结果。

>>> import numpy as np
>>> from sklearn.cluster import KMeans
>>> kmeans_model = KMeans(n_clusters=3, random_state=1).fit(X)
>>> labels = kmeans_model.labels_
>>> metrics.calinski_harabasz_score(X, labels)
561.59
数学公式#

对于大小为 \(n_E\) 的数据集 \(E\),已聚类为 \(k\) 个聚类,Calinski-Harabasz 分数 \(s\) 定义为聚类间离散度均值与聚类内离散度之比:

\[s = \frac{\mathrm{tr}(B_k)}{\mathrm{tr}(W_k)} \times \frac{n_E - k}{k - 1}\]

其中 \(\mathrm{tr}(B_k)\) 是组间离散度矩阵的迹,\(\mathrm{tr}(W_k)\) 是聚类内离散度矩阵的迹,定义如下:

\[W_k = \sum_{q=1}^k \sum_{x \in C_q} (x - c_q) (x - c_q)^T\]
\[B_k = \sum_{q=1}^k n_q (c_q - c_E) (c_q - c_E)^T\]

其中 \(C_q\) 是聚类 \(q\) 中的点集,\(c_q\) 是聚类 \(q\) 的中心,\(c_E\)\(E\) 的中心,\(n_q\) 是聚类 \(q\) 中的点数。

参考文献#

2.3.11.7. Davies-Bouldin 指数#

如果不知道基本事实标签,可以使用 Davies-Bouldin 指数(sklearn.metrics.davies_bouldin_score)来评估模型,其中较低的 Davies-Bouldin 指数对应于聚类之间分离更好的模型。

该指数表示聚类之间的平均“相似性”,其中相似性是一种度量,它比较聚类之间的距离和聚类本身的大小。

零是可能的最低分数。值越接近零表示分区越好。

在正常使用中,Davies-Bouldin 指数应用于聚类分析的结果,如下所示:

>>> from sklearn import datasets
>>> iris = datasets.load_iris()
>>> X = iris.data
>>> from sklearn.cluster import KMeans
>>> from sklearn.metrics import davies_bouldin_score
>>> kmeans = KMeans(n_clusters=3, random_state=1).fit(X)
>>> labels = kmeans.labels_
>>> davies_bouldin_score(X, labels)
0.666
数学公式#

该指数被定义为每个聚类 \(C_i\)\(i=1, ..., k\))与其最相似的聚类 \(C_j\) 之间的平均相似性。在这种指数的背景下,相似性被定义为一种度量 \(R_{ij}\),它平衡了:

  • \(s_i\),聚类 \(i\) 中每个点与该聚类质心之间的平均距离 – 也称为聚类直径。

  • \(d_{ij}\),聚类质心 \(i\)\(j\) 之间的距离。

构建 \(R_{ij}\) 使其非负且对称的一个简单选择是:

\[R_{ij} = \frac{s_i + s_j}{d_{ij}}\]

然后 Davies-Bouldin 指数定义为:

\[DB = \frac{1}{k} \sum_{i=1}^k \max_{i \neq j} R_{ij}\]
参考文献#

2.3.11.8. 列联矩阵#

列联矩阵(sklearn.metrics.cluster.contingency_matrix)报告每个真实/预测聚类对的交集基数。列联矩阵为所有聚类指标提供了足够的统计数据,其中样本是独立同分布的,并且不需要考虑某些实例未被聚类的情况。

这是一个例子:

>>> from sklearn.metrics.cluster import contingency_matrix
>>> x = ["a", "a", "a", "b", "b", "b"]
>>> y = [0, 0, 1, 1, 2, 2]
>>> contingency_matrix(x, y)
array([[2, 1, 0],
       [0, 1, 2]])

输出数组的第一行表示真实聚类为“a”的样本有三个。其中,两个在预测聚类 0 中,一个在 1 中,没有在 2 中。第二行表示真实聚类为“b”的样本有三个。其中,没有在预测聚类 0 中,一个在 1 中,两个在 2 中。

分类的 混淆矩阵 是一个方形列联矩阵,其中行和列的顺序对应于类别列表。

参考文献#

2.3.11.9. 成对混淆矩阵#

成对混淆矩阵(sklearn.metrics.cluster.pair_confusion_matrix)是一个 2x2 相似性矩阵:

\[\begin{split}C = \left[\begin{matrix} C_{00} & C_{01} \\ C_{10} & C_{11} \end{matrix}\right]\end{split}\]

通过考虑所有样本对并计算在真实聚类和预测聚类下被分配到相同或不同聚类中的对数来计算两个聚类之间的相似性。

它包含以下条目:

\(C_{00}\):两个聚类都将样本对未聚在一起的对数。

\(C_{10}\):真实标签聚类将样本对聚在一起但另一个聚类未将样本对聚在一起的对数。

\(C_{01}\):真实标签聚类未将样本对聚在一起但另一个聚类将样本对聚在一起的对数。

\(C_{11}\):两个聚类都将样本对聚在一起的对数。

将聚在一起的样本对视为阳性对,则如在二元分类中一样,真阴性计数为 \(C_{00}\),假阴性为 \(C_{10}\),真阳性为 \(C_{11}\),假阳性为 \(C_{01}\)

完美匹配的标签分配在对角线上都有非零条目,无论实际标签值如何。

>>> from sklearn.metrics.cluster import pair_confusion_matrix
>>> pair_confusion_matrix([0, 0, 1, 1], [0, 0, 1, 1])
array([[8, 0],
       [0, 4]])
>>> pair_confusion_matrix([0, 0, 1, 1], [1, 1, 0, 0])
array([[8, 0],
       [0, 4]])

将所有类别成员分配到同一聚类的标签分配是完整的,但可能并不总是纯净的,因此会受到惩罚,并具有一些非对角线的非零条目。

>>> pair_confusion_matrix([0, 0, 1, 2], [0, 0, 1, 1])
array([[8, 2],
       [0, 2]])

矩阵不是对称的。

>>> pair_confusion_matrix([0, 0, 1, 1], [0, 0, 1, 2])
array([[8, 0],
       [2, 2]])

如果类别成员完全分散到不同的聚类中,则分配完全不完整,因此矩阵的所有对角线条目都为零。

>>> pair_confusion_matrix([0, 0, 0, 0], [0, 1, 2, 3])
array([[ 0,  0],
       [12,  0]])
参考文献#