ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

ML-For-Beginners 中的 K-Means 聚类实战:用 Scikit-learn 对尼日利亚音乐数据做分簇、选 k 与质量评估

ML-For-Beginners 中的 K-Means 聚类实战:用 Scikit-learn 对尼日利亚音乐数据做分簇、选 k 与质量评估 ML-For-Beginners 中的 K-Means 聚类实战用 Scikit-learn 对尼日利亚音乐数据做分簇、选 k 与质量评估【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners本篇指南基于 ML-For-Beginners 仓库《Clustering》系列的第 2 课完整讲解如何用 Scikit-learn 的 K-Means 算法对 Spotify 抓取的尼日利亚歌曲数据集做聚类从数据预处理、特征编码到用肘部法Elbow Method确定簇数 k、用轮廓系数Silhouette Score与 WCSS/Inertia 评估簇质量再到可视化簇结果并分析方差问题。读完后你将掌握一套完整的 K-Means 建模流程并能判断一份数据是否适合用 K-Means 做聚类、以及该如何改进。核心概念K-Means 是什么它如何工作K-Means Clustering 是一种源自信号处理领域的经典聚类方法用于将数据划分为 k 个簇。它的核心思想是每个数据点都会被归入距离它最近的均值点即簇中心/质心。簇的空间结构可以可视化为 Voronoi 图——每个质心种子点与其对应的所属区域构成一块领地如上图所示。K-Means 的执行过程是一个三步循环算法先从数据集中采样选出 k 个初始中心点随后进入迭代循环循环中将每个样本分配给最近的质心再计算每个簇内所有样本的均值生成新的质心然后比较新旧质心的差异重复迭代直到质心收敛稳定。K-Means 的主要缺点是你必须事先指定 k质心/簇的数量。幸运的是肘部法Elbow Method可以帮助你估计一个合适的 k 的起始值——这正是本课实验部分要动手做的事情。本课涉及的核心术语包括Silhouette scoring轮廓系数衡量簇内紧密程度与簇间分离程度的指标取值 -1 到 1Elbow method肘部法通过 WCSS 曲线上的拐点估计最优簇数Inertia惯性簇内所有样本到其质心距离平方和的度量反映簇的内部一致性Variance方差数据点相对均值的离散程度方差过大是 K-Means 效果差的一类典型问题。数据与前置准备本课程的实现在 notebook.ipynb 中完整参考答案见 solution/notebook.ipynb。数据集是上一课Introduction to clustering中导入并清洗过的尼日利亚歌曲数据 nigerian-songs.csv——一份从 Spotify 抓取的数据共 530 行、16 列包含popularity、danceability、acousticness、energy、loudness、tempo等 Spotify 音频特征以及artist_top_genre艺人主打流派等文本列。上一课的过滤逻辑在 notebook 开头复现只保留三个流派并去掉无热度打分的歌曲import matplotlib.pyplot as plt import pandas as pd import seaborn as sns df pd.read_csv(../data/nigerian-songs.csv) # 只聚焦 3 个流派期望能聚出 3 个簇 df df[(df[artist_top_genre] afro dancehall) | (df[artist_top_genre] afropop) | (df[artist_top_genre] nigerian pop)] df df[(df[popularity] 0)]按仓库中的实际数据核对原始 530 行经过上述两步过滤后剩 286 行其中 afro dancehall 206 首、afropop 61 首、nigerian pop 19 首——三种类别本身就不均衡这一点会在后面的方差问题中再次体现。用箱线图检查离群值在建模前先体检对每一列画箱线图boxplot观察数据范围与离群点plt.figure(figsize(20,20), dpi200) plt.subplot(4,3,1) sns.boxplot(x popularity, data df) plt.subplot(4,3,2) sns.boxplot(x acousticness, data df) plt.subplot(4,3,3) sns.boxplot(x energy, data df) plt.subplot(4,3,4) sns.boxplot(x instrumentalness, data df) plt.subplot(4,3,5) sns.boxplot(x liveness, data df) plt.subplot(4,3,6) sns.boxplot(x loudness, data df) plt.subplot(4,3,7) sns.boxplot(x speechiness, data df) plt.subplot(4,3,8) sns.boxplot(x tempo, data df) plt.subplot(4,3,9) sns.boxplot(x time_signature, data df) plt.subplot(4,3,10) sns.boxplot(x danceability, data df) plt.subplot(4,3,11) sns.boxplot(x length, data df) plt.subplot(4,3,12) sns.boxplot(x release_date, data df)从参考 notebook 的标注可以看到这份数据有点吵noisy逐列观察箱线图能明显看到离群值。逐个手工剔除离群值会让数据变得过于稀疏因此课程选择了更务实的策略——挑选范围相近的列来做聚类。选列与类别编码K-Means 只接受数值特征而artist_top_genre是文本列。做法是选出范围量级相近的 6 列并用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)注意这里的选择逻辑danceability、acousticness、energy、loudness都是 Spotify 返回的 0~1或相近量级特征popularity是 0~100 的整数量级相对接近适合作为 K-Means 的输入而length毫秒十万量级、tempo几十到两百这类大范围列如果混入会主导距离计算。答案 notebook 中还额外导入了StandardScaler并对它做了注释处理见后文方差与改进一节。第一次建模KMeans 与 predict既然数据里雕刻出了 3 个流派先直接让 K-Means 聚 3 个簇试试from 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即 DataFrame 每一行被预测到的簇编号。random_state参数决定质心初始化时的随机数生成——固定种子可以让每次运行得到一致的初始质心保证实验可复现而初始化方式默认initk-means则会让初始质心彼此尽量远离通常优于纯随机初始化下一节会显式指定它。用轮廓系数Silhouette Score评估簇质量拿到预测标签后先计算一次轮廓系数from sklearn import metrics score metrics.silhouette_score(X, y_cluster_kmeans) score如何解读这个分数轮廓系数取值范围是-1 到 1越接近 1 越好得分为 1 表示簇既紧密intra-cluster 距离小又与其他簇充分分离得分接近 0 表示簇相互重叠样本落在相邻簇的决策边界附近得分为负值则意味着样本可能被分到了错误的簇。本例的得分是0.53恰好处于中间地带。这说明这份数据并不是特别适合 K-Means 这类基于紧凑球状簇假设的方法——但课程并没有就此止步而是继续走完整个评估流程看看问题究竟出在哪里。选择最优簇数WCSS、Inertia 与肘部法K-Means 必须预先给定 k那么3真的是最优解吗课程的做法是遍历 k 1~10记录每次的 WCSSWithin-Cluster Sum of Squares簇内平方和from sklearn.cluster import KMeans wcss [] for i in range(1, 11): kmeans KMeans(n_clusters i, init k-means, random_state 42) kmeans.fit(X) wcss.append(kmeans.inertia_)这段代码里有几个值得展开的要点range(1, 11)聚类过程的迭代扫描依次试验 1 到 10 个簇random_state固定随机种子决定质心初始化时的随机数生成保证结果可复现initk-meansScikit-learn 提供的优化初始化策略其原理是初始化时让质心彼此大体上远离从而通常比随机初始化得到更好的收敛结果WCSS / Inertiainertia_是 K-Means 的目标函数值——簇内所有样本到其质心距离的平方和衡量簇的内部一致性。K-Means 算法在迭代中不断调整质心以最小化 inertia每轮迭代后把该值追加进wcss列表。k 越大inertia 必然单调下降极端情况下 k n 时每个点自成一簇inertia 为 0。肘部法Elbow Method就是利用这一曲线寻找性价比拐点下降速度从陡峭转为平缓的那个位置就是增加簇数不再带来显著收益的 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()观察图中曲线的折弯bend位置即可判断最优簇数。在这个数据集上拐点确实落在了 3 附近——也就是说凭业务直觉猜测的3 个流派 3 个簇被肘部法验证了。显示簇并检查模型准确性确定 k3 后重新拟合模型并把簇以散点图显示出来from sklearn.cluster import KMeans kmeans KMeans(n_clusters 3) kmeans.fit(X) labels kmeans.predict(X) plt.scatter(df[popularity], df[danceability], c labels) plt.xlabel(popularity) plt.ylabel(danceability) plt.show()由于数据集中恰好带有流派标签artist_top_genre可以把它当作准监督信号来核对聚类的准确性——这只是探索性验证生产环境中无标签数据是没有这种捷径的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)))结果并不理想。簇的形状给出了线索三个色块彼此贴得很近、边界模糊。课程对此的总结是——这份数据过于不均衡、列与列之间相关性太弱、各列取值之间的方差又太大因此不适合直接聚类。而且形成的簇很可能被上面定义的那三个流派类别本身所主导artist_top_genre既是特征又是对照标签聚类结果自然会向它靠拢。Scikit-learn 的官方文档用一张问题模型示意图归纳了聚类数据的常见病灶像本例这种簇边界很不清晰的情况就属于其中的variance方差问题。理解方差问题与改进方向方差Variance定义为所有数据点与均值之差的平方的平均值。放到本聚类问题中它指的是数据集的数值相对各自均值离散得过于厉害——各特征列的分布形态、量级、离群情况差异明显距离度量被少数大方差维度主导K-Means 就很难切出干净的簇。课程在此给出的改进思路也是本课 Challenge 的内容进一步清洗数据比如用箱线图定位到的离群值做处理更换特征列挑选相关性更强、量级更接近的列组合换算法数据形状明显不符合紧凑球状簇假设时可考虑密度型、层次型等其他聚类方法对应本课程的 Assignment用非 K-Means 的聚类方法重新做一遍并记录结论特征缩放feature scaling这是最关键的提示。答案 notebook 里保留了一段被注释掉的StandardScaler代码from sklearn.preprocessing import LabelEncoder, StandardScaler le LabelEncoder() # scaler StandardScaler() ... # X scaler.fit_transform(X)取消注释即可对 X 做标准化缩放让各列在范围上更趋一致。课程特别指出一个反直觉现象缩放之后轮廓系数会下降但肘部图中的拐点反而变得更平滑清晰。其原因是不缩放的数据会让方差小的特征在距离计算中权重偏大、方差大的特征主导一切两者都会扭曲簇的形状标准化之后各维度的贡献趋于均衡WCSS 曲线也就更能如实反映簇结构的转折点。小结与延伸把本课的完整链路串起来就是一套可复用的 K-Means 工作流探索箱线图体检各列的范围与离群值sns.boxplot预处理筛选量级相近的数值列LabelEncoder编码类别列并留一份作对照标签初训KMeans(n_clustersk, random_stateseed)拟合后predict得到簇标签评估metrics.silhouette_score快速打分本例 0.53 提示数据与 K-Means 的适配度一般选 kk-means初始化下遍历 k 记录inertia_WCSS画肘部图找拐点本例验证了 k3诊断散点图 对照标签核对准确性识别出方差问题用StandardScaler等手段迭代改进。延伸阅读方面课程建议使用交互式 K-Means 模拟器可自行调整数据随机性、簇数与质心数直观感受质心如何迭代收敛再配合 Stanford 提供的 K-Means 讲义材料加深算法推导层面的理解。最后要强调一点本课最重要的收获——聚类效果不好本身也是有价值的结论。通过轮廓系数、肘部图和簇形状我们定位到数据不均衡、相关性弱、方差大这三个具体原因并给出了缩放、清洗、换列、换算法四条可验证的改进路径。这正是 ML-For-Beginners 这门课想传递的方法论无监督学习没有标准答案但有一套严谨的建模—评估—诊断—改进闭环。【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表