从聚类中获得的标签在视觉上看起来不正确
Posted
技术标签:
【中文标题】从聚类中获得的标签在视觉上看起来不正确【英文标题】:Labels obtained from clustering seem visually incorrect 【发布时间】:2021-02-07 04:32:54 【问题描述】:我有以下基于 10 个数据点的距离矩阵:
import numpy as np
distance_matrix = np.array([[0. , 0.00981376, 0.0698306 , 0.01313118, 0.05344448,
0.0085152 , 0.01996724, 0.14019663, 0.03702411, 0.07054652],
[0.00981376, 0. , 0.06148157, 0.00563764, 0.04473798,
0.00905327, 0.01223233, 0.13140022, 0.03114453, 0.06215728],
[0.0698306 , 0.06148157, 0. , 0.05693448, 0.02083512,
0.06390897, 0.05107812, 0.07539802, 0.04003773, 0.00703263],
[0.01313118, 0.00563764, 0.05693448, 0. , 0.0408836 ,
0.00787845, 0.00799949, 0.12779965, 0.02552774, 0.05766039],
[0.05344448, 0.04473798, 0.02083512, 0.0408836 , 0. ,
0.04846382, 0.03638932, 0.0869414 , 0.03579818, 0.0192329 ],
[0.0085152 , 0.00905327, 0.06390897, 0.00787845, 0.04846382,
0. , 0.01284173, 0.13540522, 0.03010677, 0.0646998 ],
[0.01996724, 0.01223233, 0.05107812, 0.00799949, 0.03638932,
0.01284173, 0. , 0.12310601, 0.01916205, 0.05188323],
[0.14019663, 0.13140022, 0.07539802, 0.12779965, 0.0869414 ,
0.13540522, 0.12310601, 0. , 0.11271352, 0.07346808],
[0.03702411, 0.03114453, 0.04003773, 0.02552774, 0.03579818,
0.03010677, 0.01916205, 0.11271352, 0. , 0.04157886],
[0.07054652, 0.06215728, 0.00703263, 0.05766039, 0.0192329 ,
0.0646998 , 0.05188323, 0.07346808, 0.04157886, 0. ]])
我使用以下方法将distance_matrix
转换为affinity_matrix
delta = 0.1
np.exp(- distance_matrix ** 2 / (2. * delta ** 2))
这给了
affinity_matrix = np.array([[1. , 0.99519608, 0.7836321 , 0.99141566, 0.86691389,
0.99638113, 0.98026285, 0.37427863, 0.93375682, 0.77970427],
[0.99519608, 1. , 0.82778719, 0.99841211, 0.90477015,
0.9959103 , 0.99254642, 0.42176757, 0.95265821, 0.82433657],
[0.7836321 , 0.82778719, 1. , 0.85037594, 0.97852875,
0.81528476, 0.8777015 , 0.75258369, 0.92297697, 0.99753016],
[0.99141566, 0.99841211, 0.85037594, 1. , 0.91982353,
0.99690131, 0.99680552, 0.44191509, 0.96794184, 0.84684633],
[0.86691389, 0.90477015, 0.97852875, 0.91982353, 1. ,
0.88919645, 0.93593511, 0.68527137, 0.9379342 , 0.98167476],
[0.99638113, 0.9959103 , 0.81528476, 0.99690131, 0.88919645,
1. , 0.9917884 , 0.39982486, 0.95569077, 0.81114925],
[0.98026285, 0.99254642, 0.8777015 , 0.99680552, 0.93593511,
0.9917884 , 1. , 0.46871776, 0.9818083 , 0.87407117],
[0.37427863, 0.42176757, 0.75258369, 0.44191509, 0.68527137,
0.39982486, 0.46871776, 1. , 0.52982057, 0.76347268],
[0.93375682, 0.95265821, 0.92297697, 0.96794184, 0.9379342 ,
0.95569077, 0.9818083 , 0.52982057, 1. , 0.91719051],
[0.77970427, 0.82433657, 0.99753016, 0.84684633, 0.98167476,
0.81114925, 0.87407117, 0.76347268, 0.91719051, 1. ]])
我将distance_matrix
转换为热图以获得更好的数据视觉效果
import seaborn as sns
distance_matrix_df = pd.DataFrame(distance_matrix)
distance_matrix_df.columns = [x + 1 for x in range(10))]
distance_matrix_df.index = [x + 1 for x in range(10)]
sns.heatmap(distance_matrix_df, cmap='RdYlGn_r', annot=True, linewidths=0.5)
接下来我想将affinity_matrix
分成 3 个集群。在运行实际聚类之前,我会检查热图以预测聚类。很明显,#8 是一个异常值,它本身就是一个集群。
接下来我运行实际的集群。
from sklearn.cluster import SpectralClustering
clustering = SpectralClustering(n_clusters=3,
assign_labels='kmeans',
affinity='precomputed').fit(affinity_matrix)
clusters = clustering.labels_.copy()
clusters = clusters.astype(np.int32) + 1
产出产量
[1, 1, 2, 1, 2, 1, 1, 2, 3, 2]
因此,#8 是集群 2 的一部分,集群 2 由其他三个数据点组成。最初,我会假设它本身就是一个集群。我做错什么了吗?或者有人可以告诉我为什么#8 看起来像#3、#5 和#10。请指教。
【问题讨论】:
Clustering
是一种非监督学习,因此,它可能会如你所愿,也可能不会。我认为您应该尝试其他数量的集群(为什么选择 3 个?),所以看看 here 可能会有所帮助。有很多方法可以做到这一点,有些是可视的,有些是指标,但在假设最佳集群数量之前,您绝对应该看看这些方法。
感谢您的帮助。对于此特定项目,集群的数量将始终为 2 或 3。我知道在某种程度上会有惊喜,但在距离矩阵#8 看起来它在自己的星球上,对吧?
它们看起来确实可能与其他的不同,但距离确实很近(它们从 0 到 0.14),所以这可能是一个规模问题。如果他们与其他数据点一起落入集群,我不会太自责。真诚地,我会检查它们是否适合训练数据,并可能尝试其他聚类方法。他们都是无人监督的,所以你应该经常检查他们是否做了你所期望的(如果他们做了你没想到的事情,你能从中学到什么?)
好的,但为什么#9 本身就是一个集群?直觉上没有意义。我用于缩放来自 Ng、Jordan 和 Weiss 的启发式算法,您在其中循环一系列缩放因子并选择聚类后给出最紧密(最小失真)聚类的值。
这确实是一个好问题。也许您可以绘制它的两个向量 PCA 变换以进行可视化以试图弄清楚。抱歉,如果我没有提供太多帮助。
【参考方案1】:
当我们放弃相对简单的聚类算法时,比如 k-means,我们对算法结果和预期行为的任何直觉都会崩溃;事实上,关于谱聚类的 scikit-learn documentation 给出了一个隐含的警告:
将聚类应用于归一化拉普拉斯算子的投影。
在实践中,光谱聚类在结构如下时非常有用 单个簇是高度非凸的或更一般地,当 集群的中心和散布的度量不是合适的 完整集群的描述。例如,当集群 二维平面上的嵌套圆。
现在,即使有人假装完全理解“规范化拉普拉斯算子的投影”的含义(我不会),但描述的其余部分可以说已经足够清楚,我们不应该在这里期望结果与更直观、基于距离的聚类算法(如 k-means)相似。
尽管如此,您自己的直觉并非没有根据,它表明您是否只是尝试使用 k-means 聚类而不是球形聚类;使用您的确切数据,我们得到
from sklearn.cluster import KMeans
clustering = KMeans(n_clusters=3, random_state=42).fit(affinity_matrix)
clusters = clustering.labels_.copy()
clusters = clusters.astype(np.int32) + 1
clusters
# result:
array([2, 2, 1, 2, 1, 2, 2, 3, 2, 1], dtype=int32)
确实,样本 #8 在它自己的集群 (#3) 中作为异常值脱颖而出。
尽管如此,同样的直觉并不一定适用于或对其他聚类算法有用,其价值可以说正是它们可以发现数据中不同种类的规律性——可以说,如果它们只是从现有的结果中复制结果,它们就不会那么有用像 k-means 这样的算法,对吗?
scikit-learn vignette Comparing different clustering algorithms on toy datasets 可能有助于了解不同聚类算法在一些玩具二维数据集上的行为方式;这是总结发现:
【讨论】:
以上是关于从聚类中获得的标签在视觉上看起来不正确的主要内容,如果未能解决你的问题,请参考以下文章
matlab中,用kmeans聚类之后,得到各个数据的标签,但是这个是乱序的,和真实的标签不匹配?
使用 R 中的 wordcloud 从聚类向量中显示单个 kmeans 聚类