Kmeans++、高斯混合、DBSCAN、层次聚类:用Python代码搞定你的‘非球形’数据聚类难题

张开发
2026/4/21 10:19:03 15 分钟阅读

分享文章

Kmeans++、高斯混合、DBSCAN、层次聚类:用Python代码搞定你的‘非球形’数据聚类难题
突破K均值局限Python实战四大非球形数据聚类算法当数据呈现出月牙形、环形或密度不均的复杂分布时传统K均值算法往往会陷入困境。本文将带您深入探索四种专门应对非球形数据聚类的强大算法通过Python代码实现和可视化对比掌握针对不同数据特征的对症下药技巧。1. 非球形数据聚类的挑战与解决思路在真实世界的数据分析中我们很少遇到理想化的球形数据分布。想象一下社交网络中的用户兴趣图谱、电商平台上的客户行为模式或是生物信息学中的基因表达数据——这些数据往往呈现出错综复杂的结构。传统K均值算法基于最小化簇内平方误差的假设在处理这类数据时表现捉襟见肘。非球形数据的典型特征月牙形或环形分布如sklearn的make_moons数据集密度不均匀的流形结构存在噪声点和异常值簇间大小差异显著面对这些挑战我们需要根据不同数据特性选择合适的算法from sklearn.datasets import make_moons, make_circles import matplotlib.pyplot as plt # 生成典型非球形数据集 X_moons, _ make_moons(n_samples300, noise0.05) X_circles, _ make_circles(n_samples300, factor0.5, noise0.05) fig, (ax1, ax2) plt.subplots(1, 2, figsize(12, 5)) ax1.scatter(X_moons[:, 0], X_moons[:, 1], s10) ax2.scatter(X_circles[:, 0], X_circles[:, 1], s10) ax1.set_title(月牙形数据分布), ax2.set_title(环形数据分布) plt.show()2. K-means优化初始质心的进阶版K均值虽然标准K均值对非球形数据效果有限但K-means通过改进初始质心选择策略在一定程度上提升了算法对复杂数据的适应性。K-means的核心改进随机选择第一个质心计算每个样本到最近质心的距离D(x)按概率D(x)²选择下一个质心重复步骤2-3直到选出k个质心这种策略确保初始质心分散在数据空间的不同区域减少陷入局部最优的概率。from sklearn.cluster import KMeans import numpy as np # 标准K均值 vs K-means 对比 kmeans_std KMeans(n_clusters2, initrandom, random_state42) kmeans_pp KMeans(n_clusters2, initk-means, random_state42) kmeans_std.fit(X_moons) kmeans_pp.fit(X_moons) # 可视化结果 def plot_clusters(X, labels, title): plt.scatter(X[:, 0], X[:, 1], clabels, s10, cmapviridis) plt.title(title) plt.figure(figsize(12, 5)) plt.subplot(121) plot_clusters(X_moons, kmeans_std.labels_, 标准K均值) plt.subplot(122) plot_clusters(X_moons, kmeans_pp.labels_, K-means) plt.show()适用场景数据分布接近球形但存在多个密集区域需要快速聚类解决方案作为其他算法的预处理步骤3. 高斯混合模型捕捉椭圆簇的概率方法高斯混合模型(GMM)假设数据由多个高斯分布混合生成通过EM算法估计各分布的参数能够自然地捕捉椭圆形的簇结构。GMM关键参数协方差类型full完全协方差、tied相同协方差、diag对角协方差、spherical球形协方差n_components聚类数量tol收敛阈值from sklearn.mixture import GaussianMixture # 不同协方差类型的GMM比较 cov_types [spherical, diag, tied, full] plt.figure(figsize(15, 10)) for i, cov_type in enumerate(cov_types, 1): gmm GaussianMixture(n_components2, covariance_typecov_type, random_state42) labels gmm.fit_predict(X_circles) plt.subplot(2, 2, i) plot_clusters(X_circles, labels, f协方差类型: {cov_type}) plt.scatter(gmm.means_[:, 0], gmm.means_[:, 1], markerx, s100, cred) plt.tight_layout() plt.show()BIC准则选择最佳聚类数n_components_range range(1, 10) bic_values [] for n in n_components_range: gmm GaussianMixture(n_componentsn, covariance_typefull, random_state42) gmm.fit(X_circles) bic_values.append(gmm.bic(X_circles)) plt.plot(n_components_range, bic_values, o-) plt.xlabel(聚类数量) plt.ylabel(BIC值) plt.title(BIC准则选择最佳聚类数) plt.show()适用场景数据呈现椭圆形分布需要概率化的聚类结果对聚类形状有明确先验知识4. DBSCAN基于密度的任意形状聚类DBSCAN(Density-Based Spatial Clustering of Applications with Noise)通过定义核心点和密度可达性能够发现任意形状的簇并识别噪声点。关键参数解析eps (ε)邻域半径min_samples核心点所需的最小邻域样本数from sklearn.cluster import DBSCAN # DBSCAN参数敏感性分析 eps_values [0.1, 0.15, 0.2, 0.25] min_samples_values [5, 10, 15] plt.figure(figsize(15, 10)) for i, (eps, min_samples) in enumerate([(0.1, 5), (0.2, 10), (0.15, 15), (0.25, 10)], 1): dbscan DBSCAN(epseps, min_samplesmin_samples) labels dbscan.fit_predict(X_moons) plt.subplot(2, 2, i) plot_clusters(X_moons, labels, feps{eps}, min_samples{min_samples}) n_clusters len(set(labels)) - (1 if -1 in labels else 0) plt.text(0.05, 0.95, f发现簇数: {n_clusters}, transformplt.gca().transAxes) plt.tight_layout() plt.show()DBSCAN优势与局限优势不需要预先指定簇数能识别噪声点适应任意形状的簇局限对参数敏感不适合密度差异大的数据高维数据效果下降5. 层次聚类树状结构的聚类方法层次聚类通过构建树状图(dendrogram)展示数据点间的层次关系可分为凝聚式(自底向上)和分裂式(自顶向下)两种策略。关键连接方式对比单连接(single)最小距离全连接(complete)最大距离平均连接(average)平均距离Ward方法最小化方差增量from sklearn.cluster import AgglomerativeClustering from scipy.cluster.hierarchy import dendrogram, linkage # 不同连接方式的层次聚类 linkage_methods [single, complete, average, ward] plt.figure(figsize(15, 10)) # 使用小型数据集演示 X_sample X_circles[:50] for i, method in enumerate(linkage_methods, 1): agg AgglomerativeClustering(n_clusters2, linkagemethod) labels agg.fit_predict(X_sample) plt.subplot(2, 2, i) plot_clusters(X_sample, labels, f连接方式: {method}) plt.tight_layout() plt.show() # 绘制树状图 plt.figure(figsize(10, 7)) linked linkage(X_sample, ward) dendrogram(linked, orientationtop, distance_sortdescending) plt.title(层次聚类树状图(Ward方法)) plt.show()层次聚类特点可视化直观树状图不需要预先指定簇数计算复杂度较高O(n³)或O(n²)适合中小规模数据集6. 算法对比与实战选择指南为帮助您在实际项目中做出明智选择我们总结四大算法的关键特性算法特性对比表特性K-means高斯混合模型DBSCAN层次聚类簇形状假设球形椭圆任意取决于连接方式处理噪声能力弱中等强弱参数敏感性中等中等高中等计算复杂度O(n)O(n²)O(n log n)O(n³)是否需要预设簇数是是否可选适合数据规模大规模中等规模中等规模小规模实战选择建议当数据近似球形且需要快速结果 → K-means数据呈椭圆形分布且有概率解释需求 → 高斯混合模型复杂形状、含噪声数据 → DBSCAN需要层次关系可视化 → 层次聚类# 综合对比示例 from sklearn.metrics import silhouette_score algorithms { K-means: KMeans(n_clusters2, initk-means, random_state42), GMM: GaussianMixture(n_components2, covariance_typefull, random_state42), DBSCAN: DBSCAN(eps0.2, min_samples10), 层次聚类: AgglomerativeClustering(n_clusters2, linkageward) } plt.figure(figsize(15, 10)) for i, (name, algo) in enumerate(algorithms.items(), 1): if name GMM: labels algo.fit(X_moons).predict(X_moons) else: labels algo.fit_predict(X_moons) plt.subplot(2, 2, i) plot_clusters(X_moons, labels, name) if -1 not in labels: # 排除噪声点计算轮廓系数 score silhouette_score(X_moons, labels) plt.text(0.05, 0.95, f轮廓系数: {score:.2f}, transformplt.gca().transAxes) plt.tight_layout() plt.show()在实际项目中我经常采用两步走策略先用DBSCAN探索数据结构和可能的簇数再根据结果选择更精确的算法进行细化分析。这种方法在客户细分项目中特别有效能够避免预设簇数带来的主观偏差。

更多文章