
在 ML-For-Beginners 中让聚类不再依赖 K-Means基于尼日利亚歌曲数据集实践层次、密度与分布型聚类【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners本篇技术指南围绕 translations/bn/5-Clustering/2-K-Means/assignment.md 这份课后作业展开在学习了 K-Means 聚类之后尝试使用一种不是 K-Means 的聚类算法在同一份数据上建模并记录学习收获。文章会先完整还原 5-Clustering/2-K-Means/README.md 中的基线流程数据清洗、特征选择、K-Means、轮廓系数、肘部法则再结合 5-Clustering/1-Visualize/README.md 给出的 Scikit-learn 聚类方法地图逐一手把手实现层次凝聚聚类、DBSCAN 与高斯混合模型三种替代方案。读完本文你将能够独立完成该作业、对聚类结果做轮廓系数与标签一致性评估并理解什么时候 K-Means 不适用、该换哪种算法。作业任务解读这门课后练习到底要求什么该作业的原文指令翻译如下本课中你已经学习了 K-Means 聚类。有时 K-Means 并不适合你的数据。请创建一个 notebook使用本课或其他来源的数据请注明来源展示一种不使用 K-Means的聚类方法。你学到了什么作业的评分标准Rubric为三档标准优秀Exemplary合格Adequate需改进Needs Improvement整体交付提交一个带有良好文档说明的聚类模型 notebook提交的 notebook文档不完整和/或内容不完整提交了未完成的工作由此可以看出作业的完成度评判核心不在模型精度多高而在三件事选择了非 K-Means 的算法、过程有据可查、对结果有自己的解读。这也与 5-Clustering/1-Visualize/README.md 强调的主旨一致聚类是探索性分析你选用的方法取决于你的数据。要完成它最好的切入点就是本仓库已经准备好的 nigerian-songs.csv 数据集、上一课的 1-Visualize/notebook.ipynb完成数据导入与清洗以及本课的 2-K-Means/notebook.ipynb完成特征挑选与 K-Means 基线。仓库在 solution 目录下还提供了答案参考notebook.ipynb、tester.ipynb以及 R/Julia 实现可作为提交前对照。前置准备数据从哪来、基线怎么打加载并理解数据作业允许使用本课数据或其他来源数据注明来源。最省事且最能和课程结论对话的选择就是本课数据集import matplotlib.pyplot as plt import pandas as pd import seaborn as sns # 相对本课目录 5-Clustering/2-K-Means/ 的上级 data 目录 df pd.read_csv(../data/nigerian-songs.csv) df.head()该数据集包含 530 行、16 列曲名、专辑、艺人、艺人主流派、发行年份、时长、流行度以及 danceability、acousticness、energy、instrumentalness、liveness、loudness、speechiness、tempo、time_signature 等 Spotify 音频特征这是 1-Visualize/README.md 中df.info()的输出内容其中 8 列为 float64、4 列为 int64、4 列为 object全表无空值。K-Means 课延续上一课的数据清洗结论只保留afro dancehall、afropop、nigerian pop三个占主导的流派并剔除popularity 0无排名的噪声的记录df df[(df[artist_top_genre] afro dancehall) | (df[artist_top_genre] afropop) | (df[artist_top_genre] nigerian pop)] df df[(df[popularity] 0)]上一课的探索还发现一个关键事实数据整体相关性很弱唯一较强相关的是energy与loudness大声的音乐通常能量感强。这意味着聚类算法能从这份数据中读出的结构有限为后续 K-Means 表现不佳埋下伏笔——这也正是本作业选择替代算法的动机来源。用箱线图观察离群值在 K-Means 课程的准备环节脚本对popularity、acousticness、energy、instrumentalness、liveness、loudness、speechiness、tempo、time_signature、danceability、length、release_date共 12 个特征逐列绘制sns.boxplot参见 2-K-Means/notebook.ipynbplt.figure(figsize(20,20), dpi200) plt.subplot(4,3,1) sns.boxplot(x popularity, data df) # ... 依次对每个特征重复 subplot boxplot ... plt.subplot(4,3,12) sns.boxplot(x release_date, data df)结论是数据有些嘈杂每个特征列都存在明显的离群点。课程给出的处理策略是不要彻底删除离群值——那会让数据量变得过小而是选择量纲相近的列参与聚类。构造特征矩阵 X 与编码标签基线做法选择artist_top_genre、popularity、danceability、acousticness、loudness、energy六个特征并用LabelEncoder将流派字符串转为数值from sklearn.preprocessing import LabelEncoder le LabelEncoder() X df.loc[:, (artist_top_genre,popularity,danceability, acousticness,loudness,energy)] y df[artist_top_genre] X[artist_top_genre] le.fit_transform(X[artist_top_genre]) y le.transform(y)注意这里y虽被编码但它只是用来事后核对聚类结果与真实流派的吻合度聚类本身无监督并不消费标签。K-Means 基线3 个簇 轮廓系数数据集只保留了 3 个主流流派因此先试n_clusters 3from sklearn.cluster import KMeans nclusters 3 seed 0 km KMeans(n_clustersnclusters, random_stateseed) km.fit(X) y_cluster_kmeans km.predict(X) y_cluster_kmeans输出是一个数组每行数据对应一个预测簇标签0、1 或 2。接着用轮廓系数silhouette score评估聚类质量from sklearn import metrics score metrics.silhouette_score(X, y_cluster_kmeans) score轮廓系数取值范围为 -1 到 1越接近 1 表示簇内稠密、簇间分离清晰接近 0 表示簇与簇重叠样本紧贴相邻簇的决策边界。课程中该模型得分约为0.53刚好在中间说明数据并不特别适合这种基于质心、球状假设的聚类方式——但课程为了教学仍然继续了下去。用肘部法则验证 k 的选择因为知道有 3 个流派就选 3 个簇只是一种猜测需要用肘部法则验证。思路是对 k 从 1 到 10 逐一运行 K-Means记录每次的组内平方和WCSS / inertiafrom sklearn.cluster import KMeans wcss [] for i in range(1, 11): kmeans KMeans(n_clustersi, initk-means, random_state42) kmeans.fit(X) wcss.append(kmeans.inertia_)对这段代码涉及的关键参数课程有明确注释range(1, 11)聚类过程的迭代次数集合random_state决定质心初始化的随机数生成方式固定后可复现WCSSwithin-cluster sums of squares簇内所有点到簇质心的平方平均距离inertiaK-Means 试图最小化的目标即簇内部一致程度的度量每次迭代后被追加进wcss变量k-meansScikit-learn 提供的质心初始化优化让初始质心彼此大体上远离通常优于纯随机初始化。绘制 k 与 WCSS 的折线图弯折处肘部对应的 k 即最优簇数plt.figure(figsize(10,5)) sns.lineplot(xrange(1, 11), ywcss, markero, colorred) plt.title(Elbow) plt.xlabel(Number of clusters) plt.ylabel(WCSS) plt.show()该图与 images/elbow.png 一致地表明3 或许确实是一个合理取值。展示簇并评估精度以 3 个簇重新拟合后用popularity与danceability做散点并给不同簇着色from sklearn.cluster import KMeans kmeans KMeans(n_clusters3) kmeans.fit(X) labels kmeans.predict(X) plt.scatter(df[popularity], df[danceability], clabels) plt.xlabel(popularity) plt.ylabel(danceability) plt.show()再拿簇标签与真实流派编码对比计算正确率labels kmeans.labels_ correct_labels sum(y labels) print(Result: %d out of %d samples were correctly labeled. % (correct_labels, y.size)) print(Accuracy score: {0:0.2f}.format(correct_labels/float(y.size)))课程的结论是模型准确率并不理想散点图中簇的形状已经暗示了原因——这份数据过于不均衡、特征之间相关度太低、各列取值方差过大因此难以聚出清晰边界实际形成的簇很可能被我们事先划定的三个流派标签严重带偏见 images/clusters.png 的效果图。在 Scikit-learn 的文档语境里这种簇边界不清晰的模型被称为存在variance方差问题数据中各数值相对均值偏离过大。为什么 K-Means 在这里表现不佳K-Means 的硬伤可以总结为四点这也是作业要求你另寻算法的全部理由必须预先指定 k虽然肘部法则能给出参考但参考不等于正确答案簇形状假设为凸/球状对非球形、长条形、嵌套形簇无能为力对量纲敏感各特征取值范围差异大时方差大的特征会主导距离计算不擅长处理噪声与密度不均所有点都会被硬性划入某个簇没有噪声点概念。上一课 1-Visualize/README.md 将上述问题概括得更体系化簇可以是flat/non-flat geometry欧氏/非欧氏几何、transductive/inductive转导/归纳、constrained带约束、density密度型等不同性质K-Means 只覆盖其中很小一类。替代算法路线图Scikit-learn 给了你哪些选项依据 1-Visualize/README.md 中列出的方法对照表除去 K-Means适合本作业换一种方法的候选及其适用场景是方法适用场景仓库文档原文含义Affinity propagation亲和传播簇多、簇大小不均归纳式Mean-shift均值漂移簇多、簇大小不均归纳式Spectral clustering谱聚类簇少、簇大小均匀转导式Ward hierarchical clusteringWard 层次聚类簇多、存在约束转导式Agglomerative clustering凝聚层次聚类簇多、存在约束、支持非欧氏距离转导式DBSCAN非平坦几何、簇大小不均、存在噪声转导式OPTICS非平坦几何、密度可变的簇转导式Gaussian mixtures高斯混合平坦几何归纳式BIRCH带离群点的大规模数据集归纳式按算法家族划分同样源自该课层次聚类hierarchical对象根据与相邻对象的接近程度归类Scikit-learn 的凝聚聚类属于此类质心聚类centroidK-Means 为代表需指定 k分布型聚类distribution-based基于统计建模判断数据点属于某簇的概率高斯混合方法属于此类密度型聚类density-based按点与点之间的密度聚集远离群体的点被视为离群点/噪声DBSCAN、Mean-shift、OPTICS 属于此类。下方三种方案分别从层次、密度、分布三类中各取一个代表性算法全部可直接照抄进你的作业 notebook。方案 A层次凝聚聚类AgglomerativeClusteringWard 连接层次聚类不需要预设距离是到质心的欧氏距离这种球状假设而是从每个样本各自成簇开始按相似度逐层合并。Scikit-learn 中 Ward 连接以最小化合并时簇内方差增量为目标与 K-Means 的最小化 inertia 思路在数学上同源但聚类方式完全不同——它是转导式的直接对给定样本分组不产出可推广到新样本的模型。from sklearn.cluster import AgglomerativeClustering from sklearn import metrics # 先用与 K-Means 相同的 n_clusters3 保持可比性 agg AgglomerativeClustering(n_clusters3, linkageward) labels_agg agg.fit_predict(X) score_agg metrics.silhouette_score(X, labels_agg) print(Agglomerative silhouette:, round(score_agg, 3)) # 与真实流派对照 correct_agg sum(y labels_agg) print(Matched samples: %d / %d % (correct_agg, y.size))比 K-Means 更进一步凝聚聚类还可以用**树状图dendrogram**直接观察合并过程不需要提前拍脑袋定 k。Scikit-learn 不直接提供画树状图的 API需要借助 SciPyfrom scipy.cluster.hierarchy import dendrogram, linkage from scipy.spatial.distance import pdist # 基于 Ward 连接的层次结构 Z linkage(pdist(X), methodward) plt.figure(figsize(12, 6)) dendrogram(Z, truncate_modelevel, p5) plt.title(Hierarchical Clustering Dendrogram (Ward)) plt.xlabel(Sample index / (cluster size)) plt.ylabel(Distance) plt.show()观察树状图中最大的纵向间隙可以佐证数据到底分几簇更自然这正是作业展示不同方法并说明学到了什么的理想素材。方案 B密度型聚类DBSCANK-Means 会给每个点硬分配一个簇DBSCAN 则完全不同它把点划分为核心点、边界点与噪声点噪声点会被标记为-1而不是被硬塞进某个簇。这对本数据集的现实意义很大——上一课已指出数据存在大量离群点而离群点是否应该拥有一个簇标签本身就是值得在作业里讨论的问题。from sklearn.cluster import DBSCAN # eps 控制邻域半径min_samples 控制成为核心点所需的最少邻居数 db DBSCAN(eps3, min_samples10) labels_db db.fit_predict(X) n_noise list(labels_db).count(-1) n_clusters_db len(set(labels_db)) - (1 if -1 in labels_db else 0) print(DBSCAN found %d clusters, %d noise points % (n_clusters_db, n_noise)) # DBSCAN 结果包含 -1直接计算 silhouette 需要剔除噪声点 mask labels_db ! -1 if mask.sum() 1 and len(set(labels_db[mask])) 1: score_db metrics.silhouette_score(X[mask], labels_db[mask]) print(DBSCAN silhouette (excluding noise):, round(score_db, 3))eps与min_samples是 DBSCAN 的两个超参数eps过小会导致几乎全是噪声过大则把所有点并成一簇min_samples越大越容易把稀疏区域判为噪声。由于它们对结果影响显著一个诚实的做法是在一定范围上网格搜索并记录不同参数下的簇数、噪声点占比与轮廓系数把参数敏感性写进作业的文档说明中。import numpy as np for eps in [2, 3, 5, 8]: for min_samples in [5, 10, 20]: db DBSCAN(epseps, min_samplesmin_samples).fit(X) labels_tmp db.labels_ n_clu len(set(labels_tmp)) - (1 if -1 in labels_tmp else 0) n_noi int((labels_tmp -1).sum()) print(eps%.1f min_samples%2d - clusters%d, noise%d % (eps, min_samples, n_clu, n_noi))方案 C分布型聚类高斯混合模型GaussianMixture高斯混合模型把数据看成若干个高斯分布的叠加输出的是每个点属于每个簇的概率软分配而不是 K-Means 那样的硬 0/1 标签。它可以拟合椭圆状、大小不均的簇并且在密度聚类认为该点是噪声的地方仍能给出一个带概率的归属——这正好回应了作业开头的提示K-Means 有时不合适。from sklearn.mixture import GaussianMixture # 与前面的 n_clusters 保持一致取 3 个分量 gmm GaussianMixture(n_components3, random_state0) gmm.fit(X) labels_gmm gmm.predict(X) proba_gmm gmm.predict_proba(X) # 每行的软分配概率 score_gmm metrics.silhouette_score(X, labels_gmm) print(GaussianMixture silhouette:, round(score_gmm, 3)) print(Mean max membership probability:, round(proba_gmm.max(axis1).mean(), 3)) # 与真实流派对照 correct_gmm sum(y labels_gmm) print(Matched samples: %d / %d % (correct_gmm, y.size))predict_proba返回的是 n_samples × n_components 的概率矩阵某簇的最大后验概率普遍偏低说明大量样本在两个流派特征带之间模糊重叠——这一观察可以直接写进作业的你学到了什么。共通教训特征缩放是绕不开的一步课程 Challenge 与 Review 部分都反复提示了特征缩放课程指出不做缩放的代码里留有被注释的标准化步骤一旦启用标准缩放轮廓系数会下降而肘部曲线的拐点会变平滑。原因在于不缩放时方差更大的特征会在欧氏距离中携带更高权重掩盖了其他特征的信息缩放后各列回归到同一量纲聚类反映的才是综合特征结构而非单一特征。因此无论选方案 A/B/C都建议在作业里做一组缩放前 vs 缩放后的对照实验from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline # 特征缩放 任一聚类器组合为管道避免数据泄漏 scaler StandardScaler() X_scaled scaler.fit_transform(X) # 例对缩放后的数据重跑层次聚类 agg_scaled AgglomerativeClustering(n_clusters3, linkageward) labels_agg_scaled agg_scaled.fit_predict(X_scaled) print(Agglomerative silhouette (scaled):, round(metrics.silhouette_score(X_scaled, labels_agg_scaled), 3)) # 例对缩放后的数据重跑高斯混合 gmm_scaled GaussianMixture(n_components3, random_state0) labels_gmm_scaled gmm_scaled.fit_predict(X_scaled) print(GaussianMixture silhouette (scaled):, round(metrics.silhouette_score(X_scaled, labels_gmm_scaled), 3))把四种结果K-Means、Agglomerative、DBSCAN、GMM × 原始/缩放整理成一张对比表是让作业达到优秀档位的最直接方式。对照评分细则自查与文档化建议对照作业的 Rubric可以从以下三个层面自查 notebook 是否达到Exemplary选用了非 K-Means 的聚类方法优先展示一个从头到尾完整跑通的算法层次/密度/分布三选一即可代码注释说明参数含义与选取依据文档完整每个代码块前后用 Markdown 说明在做什么、预期输出、为什么这么做至少包含数据来源声明如数据取自本仓库 5-Clustering/data/nigerian-songs.csv出自 ML-For-Beginners 聚类课程、一次 silhouette 或其他内部指标评估、一次与已知流派的标签对照分析有你学到了什么的结论段把课程的结论复述并验证——例如本数据相关性弱、量纲差异大、三类流派特征带相互重叠导致无论 K-Means 还是替代算法都难以得到高轮廓系数此时聚类更适合用作探索性工具而非分类器这一认知本身就是作业要的训练目标。若想进一步提高聚类质量可沿课程 Challenge 的方向继续清理更多离群点、换用不同的特征组合例如只取相关度更高的energy/loudness、对样本加权等。仓库的 solution/notebook.ipynb 与 solution/tester.ipynb 提供了参考答案与自动评测脚本R 语言学习者还可参考 solution/R/lesson_15-R.ipynb其中还给出了 K-Means 的完整五步迭代描述分配、重算质心、再分配直到质心几乎不再移动。小结本作业的真正价值不在于找出一个比 K-Means 更准的模型而在于体验方法选择依赖数据性质这一无监督学习的核心方法论。K-Means 教程用尼日利亚歌曲数据给出了 0.53 的轮廓系数与不理想的标签吻合度恰恰为替代算法提供了绝佳的对照基线而层次聚类让你看到合并层级、DBSCAN 让你直面噪声点、高斯混合让你获得软概率分配三种视角互补共同构成对同一份难聚数据的完整画像。按上文步骤完成建模、评估、缩放对照与文档化即可交付一份符合仓库作业评分标准的高质量 notebook。【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考