我们可以通过对一系列曲目进行聚类来创建歌曲的自动播放列表,我们可以展示如何自动创建相似歌曲的子组。通过我们现有的歌曲知识,我们能够验证该聚类练习的结果。
但是,如果我们对数据没有这种先验知识怎么办?如果数据甚至都没有被标记怎么办(在许多实际的聚类案例中就是这种情况)?即使是这样,如果这些标签最初对我们没有意义,该怎么办?有很多我从未听说过的艺术家,如果我们要对数千首曲目进行分组,那么手动验证每个集群显然是不切实际的。在这些情况下,我们需要某种数学方法来衡量聚类的"成功"程度。
为了探索如何做到这一点,我们再次转向Spotify的API。假设我们从四个完全不同的播放列表中选取歌曲:
- Rap UK
- Smooth Jazz
- Classical Essentials
- Essential K-Pop
如果我们将它们合并到一个数据集中,则无监督的机器学习算法应该能够将其歌曲分组为四个群集,这些群集在某种程度上类似于原始的四个播放列表。
在开始之前,我们确实可能需要检查一下我们的假设,即来自这些不同播放列表的歌曲确实"与众不同"。当然,在单个图表上同时可视化两个以上的特征是一项挑战。但是,如果我们绘制所有功能的散布矩阵,并按播放列表进行颜色编码,则可以看到有很多度量组合可以证明每种流派的独特特征。
我们在上中看到,在Scikit-Learn中运行聚类算法非常简单:
#We scale the data to ensure that
#feature units don't impact distances
from sklearn.preprocessing import StandardScaler
sclaer = StandardScaler()
X_scaled = scaler.fit_transform(X)#This scaled data can then be fed into the HAC algorithm
from sklearn.cluster import AgglomerativeClustering
#We can tell it how many clusters we're aiming for
agg_clust = AgglomerativeClustering(n_clusters=4)
assigned_clusters = agg_clust.fit_predict(X_scaled)
我们还看到,HAC具有三个不同的"链接标准",即该算法将群集逐渐连接在一起的方法:
- ward(默认):选择两个聚类,以所有聚类中的方差增加最小的方式合并。通常,这会导致大小相当相等的群集。
- complete(或最大链接):合并两个点之间最大距离最小的两个聚类。
- ·average:合并所有点之间平均距离最小的两个聚类。
让我们看看这三个链接标准如何处理类型播放列表数据集。我们用矩阵表示结果,显示每个播放列表的歌曲在每个群集中所占的百分比(群集被任意命名为" A"," B"," C"和" D")。
当然,如果聚类是完美的,我们希望矩阵的每一行和每一列都恰好包含一个100%的条目(当然,它不需要成对角线,因为聚类名称的分配是任意的)。
默认的"向后"链接试图最小化群集中的方差,尽管这四个群集都有一些泄漏,但在所有四种类型中都表现出色。
"完全"链接显然效果不佳。它已将许多数据集放入群集A。群集C由一首说唱歌曲组成。
"平均"链接与"完全"链接具有类似的问题。许多数据点已放置在一个群集中,其中两个群集由一首歌曲组成。
值得一提的是,还有另一种常见的聚类类型,即K-Means,其工作原理略有不同。HAC通过将它们合并在一起来迭代地减少聚类的数量,而K-Means聚类保持固定数量的聚类(名义上的k),但是迭代地更改每个聚类的成员。
每个群集的"中心"由带有黑色" +"号的"大"标记表示。所有点都分配给它们最接近中心的聚类。在此分配步骤之后,将重新计算群集中心以包括新成员,然后发生另一个重新分配步骤。如果在重新分配步骤中没有点更改聚类,则算法结束(动画:)。
K-Means很容易在Python中实现:
#We scale the data to ensure that
#feature units don't impact distances
from sklearn.preprocessing import StandardScaler
sclaer = StandardScaler()
X_scaled = scaler.fit_transform(X)#This scaled data can then be fed into the K-Means alorithm
from sklearn.cluster import KMeans
#We can tell it how many clusters we're aiming for
km_clust = KMeans(n_clusters=4)
assigned_clusters = km_clust.fit_predict(X_scaled)
如果将K-Means聚类应用于播放列表数据集,则会得到以下信息:
与使用"ward"链接的HAC算法一样,K-Means聚类在大多数算法中都做得很好,一些爵士乐和说唱歌曲对K-Pop来说是"错误的"。
尽管这些矩阵可以很好地"盯住"我们的结果,但它们在数学上还不够严格。让我们考虑一些指标,这些指标实际上可以帮助我们为集群质量分配一个数字。
调整后的Rand Index(兰德指数)
该是对经典兰德指数的变化,并试图表达什么群集分配比例是"正确"。通过考虑所有样本对,并根据预测的真实聚类对分配在预测的相同或不同聚类中的对进行计数,并针对随机机会进行调整,计算出两个不同聚类之间的相似性度量。
可以使用Scikit-Learn评估此(以及我们将考虑的其他指标)。
from sklearn import metrics
metrics.adjusted_rand_score(predicted_labels, actual)
调整后的兰德指数限制在-1和1之间。接近1表示好,而接近-1表示差。
我们看到K均值和Ward Linkage得分很高。基于我们先前观察到的矩阵,我们期望得到这一结果。
Fowlkes Mallows Score
该是相似的,在尽可能多的,它会告诉你哪个集群分配是"正确"的程度。特别是,它计算精度和召回率之间的几何平均值。它的范围是0到1,值越高越好。
metrics.fowlkes_mallows_score(predicted_labels,actual)
我们的排名与调整后的兰德指数相似,这是我们期望的,因为它们是尝试回答同一问题的两种方法。
值得注意的是,我们需要了解原始标签才能计算这些指标。鉴于处理无标签数据是无监督学习的主要用例之一,因此我们需要一些其他指标来评估聚类结果,而无需引用"真实"标签。
假设我们从三个单独的聚类分析中得到以下结果。
显然,我们可以使集群更加"紧密"。是否可以通过某种方式将这种"紧度"归因于数字?
轮廓分数
该试图描述一个数据点的相似程度在其集群的其他数据点,相对于数据点并不在其集群(这是汇聚了所有数据点来获得总体集群分数)。换句话说,它考虑了集群在空间中的"区别度"-实际上人们可以使用任何"距离"度量来计算分数。
它的范围是-1和1。接近-1表示群集不正确,而接近+1则表示每个群集都非常密集。
metrics.silhouette_score(scaled_feature_data,cluster_labels)
我们看到,所有聚类都没有超高的轮廓分数。有趣的是,我们看到平均链接集群的得分最高。但是请记住,该算法产生了两个群集,每个群集仅包含一个数据点,这在现实情况下不太可能是理想的结果(这是一个教训,您通常不能依靠单个指标来做出决策算法的质量!)
Calinski Harabaz指数
所述Calinski Harabaz指数是相对于点的数据点的方差相比,在其它簇的点的比率,对所述方差中的集群。由于我们希望第一部分较高,而第二部分较低,因此需要较高的CH指数。与我们看到的其他指标不同,此分数没有界限。
metrics.calinski_harabasz_score(scaled_feature_data,cluster_labels)
在这里,我们看到我们的K均值和Ward Linkage算法得分很高。完全和平均链接算法因具有一个或两个较大的聚类而受到惩罚,这将具有较高水平的内部方差。