ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

聚类算法全解析:从k-means到子空间聚类的实战指南

聚类算法全解析:从k-means到子空间聚类的实战指南 1. 聚类技术发展历史1.1 从分类学到聚类思想起源聚类这事本质上不是计算机科学发明的而是统计学和人类学早就有的需求。你想想生物学家要对物种分门别类考古学家要对出土器物分组心理学家要对人群做类型划分这些都是“把相似的东西放一起”的操作。1932年人类学家Driver和Kroeber在研究文化特质分布时已经开始用简单的相似性矩阵来做分组这算是聚类思想最早的雏形之一。但那时候没有计算机全靠手工算距离、画树状图工作量极大能做的样本量也就几十个。真正让聚类变成一门计算学科要等到1950年代计算机普及之后。1957年Lloyd在贝尔实验室提出了脉冲编码调制中的一种量化算法后来被证明就是k-means的雏形。1967年MacQueen正式在论文里使用了“k-means”这个术语并讨论了聚类中心更新的思想。这里有个很有意思的点Lloyd的论文其实是以贝尔实验室内部技术报告形式存在的直到1982年才正式公开发表所以很多人引用时会把年份写成1957或1982两个都对看你在意的是首次提出还是正式发表。1.2 关键时间线1950年代至今我把整个发展脉络梳理成几个关键节点这样对照着看会清晰很多时间段代表性工作核心贡献1950s–1960sLloyd算法、MacQueen的k-means术语、Sokal Sneath数值分类学奠定划分式聚类和数值分类基础1960s–1970s层次聚类算法体系成型single-link、complete-link、Ward等系统化的层次聚类与树状图可视化1970s–1980sEM算法应用于混合模型聚类、模糊c-meansBezdek引入概率模型和软聚类思想1990sDBSCANEster et al. 1996、BIRCH1996、CURE1998解决任意形状簇、大规模数据聚类问题2000s谱聚类Shi-Malik 2000, Ng et al. 2002、子空间聚类把图论和流形学习引入聚类2010s至今深度聚类、大规模分布式聚类、自动聚类借助表示学习和算力突破处理非结构化数据这几十年的演进核心线索其实就一条数据越来越复杂聚类方法越来越能处理“非球形、高维、大规模、噪声多”的数据。早期k-means只能处理凸形簇DBSCAN解决了任意形状谱聚类把非线性结构映射到低维空间再分子空间聚类则专门对付高维数据。理解这条主线再看各种算法时就不会觉得是一堆孤立方法堆在一起。2. 聚类算法主要分类2.1 基于划分的方法k-means及其变体基于划分的方法思路一句话把n个样本分到k个簇中让每个样本到其簇中心的距离平方和最小。最典型的就是k-means流程很简单随机选k个初始中心迭代分配样本到最近中心再重新计算中心直到收敛。这里有个细节经常被初学者忽略——k-means求解的是NP难问题的局部最优近似解初始中心选不好很容易陷入局部最优所以实际中会用k-means初始化或者多次随机重启。k-means的变体多到数不过来k-medoids用真实样本替代均值中心对离群点更鲁棒、k-modes专门处理分类属性、fuzzy c-means软聚类样本以隶属度形式属于多个簇、bisecting k-means每次二分一个簇常用于文本聚类加速。选用哪个取决于数据形态和业务需求不是越复杂越好。2.2 基于层次的方法从下往上还是从上往下层次聚类分两种凝聚式agglomerative从每个样本单独成簇开始逐步合并最近的两个簇分裂式divisive则反过来从一个全量大簇开始递归拆分。实际中99%的场景用的是凝聚式也就是热词里提到的“全链接聚类”。合并时如何定义“簇间距离”决定了算法的行为单链接single-link取两个簇中最近样本的距离容易产生链式效应把本不相关的样本串成一簇。全链接complete-link取两个簇中最远样本的距离对噪声更敏感但簇形状更紧凑。平均链接average-link取所有样本对距离的平均是折中方案实践中用得最多。Ward方法合并后簇内离差平方和增量最小相当于目标函数导向的层次版k-means。层次聚类的最大好处是不用预先指定k值直接看树状图dendrogram切一刀就能得到不同粒度的聚类结果。代价是复杂度高经典实现是O(n³)优化后也要O(n² log n)样本上万后比较吃力。2.3 基于密度的方法DBSCAN与OPTICS基于密度的方法核心假设是簇是样本密集连通的区域被稀疏区域分隔开。DBSCAN只需要两个参数邻域半径eps和最小样本数minPts。它在聚类的同时还能标记噪声点这是划分法和层次法都做不到的——k-means会把噪声也硬分到一个簇里层次聚类对噪声同样无解。DBSCAN有个经典痛点eps不好调。数据分布密度不均匀时单一全局eps要么把稀疏簇丢掉要么把密集簇合并。OPTICS算法改进了这个问题它不直接给出聚类结果而是输出一个可达距离图相当于一个可调参数的全景扫描。另一个方向是HDBSCAN用层次结构替代固定eps实际效果在不少数据集上比DBSCAN稳很多也是我这几年做项目时的首选密度聚类工具。2.4 基于网格与模型的方法效率和假设的权衡网格聚类如STING、CLIQUE把数据空间划分成网格单元在网格上做统计和聚类优点是计算量与样本数解耦适合大规模数据但精度受网格分辨率影响。模型聚类则假设数据由若干统计分布生成典型是高斯混合模型GMM配合EM算法求解。GMM给出的是样本属于每个簇的后验概率属于软聚类比k-means多了一层不确定性信息。GMM比较适合数据本身呈高斯分布的场景比如图像像素的颜色分割、金融数据的收益率建模。但要注意EM算法的初始参数同样影响结果而且高斯分量个数即k值一样要提前定这点和k-means没有本质区别。2.5 子空间聚类与高维挑战高维数据是聚类的噩梦这也是热词里“子空间聚类”频繁出现的原因。所谓维度灾难是指在10维、50维、100维空间里样本之间的距离趋近于均匀传统距离度量的区分能力急剧下降。而且很多高维数据比如基因表达谱、文本词频矩阵真正有效的结构往往只存在于某个低维子空间中。子空间聚类的目标就是同时找到样本的分组和每个分组所在的特征子集。早期有CLIQUE这种网格与密度结合的自适应子空间方法后来更主流的是谱系子空间聚类先构建样本间的亲和矩阵再用谱聚类的大框架求解。Elhamifar和Vidal在2009年提出的稀疏子空间聚类SSC是这类方法的代表作它的核心假设是每个样本可以由同一子空间中其他样本的稀疏线性组合表示通过l1范数优化求出亲和矩阵再做谱聚类。这篇论文后来在运动分割、人脸聚类、图像分割等领域影响非常大。3. 重要论文解析3.1 k-means与Lloyd算法一切的基础虽然k-means简单到看起来不像学术问题但它确实是无数工业系统的基础。Lloyd的原始论文《Least Squares Quantization in PCM》讨论的是信号量化但算法流程完全就是k-means。MacQueen 1967年的论文则从数学上把k-means定义为一个把样本划分到k个类、使类内平方和最小的过程。这里我建议真正要搞聚类的人花点时间读一下MacQueen原文和Arthur Vassilvitskii 2007年的k-means论文。k-means这篇虽然短但它解决了困扰k-means几十年的初始化问题思路极其朴素第一个中心随机选后续中心以正比于“样本到最近已选中心的距离平方”的概率选取。这个改动让初始化分散度大幅提升收敛速度和解质量都有显著改善而且实现起来就十几行代码性价比极高。3.2 DBSCAN密度聚类里程碑Ester、Kriegel、Sander和Xu在KDD 1996上发表的《A Density-Based Algorithm for Discovering Clusters in Large Spatial Databases with Noise》被引超过两万次是数据挖掘领域被引最高的论文之一。论文重新定义了“簇”一个簇是密度相连的点的最大集合。通过核心点邻域内样本数≥minPts、边界点落在核心点邻域内但不是核心点、噪声点其余三个概念DBSCAN天然解决了噪声识别和任意形状聚类两个问题。这篇论文的另一个贡献是把空间索引R*-tree用于加速邻域查询这让DBSCAN在大型空间数据库上变得可行。虽然后来R*-tree这种结构在内存计算时代用得少了但“用空间索引加速距离查询”的思路在KNN图构建、谱聚类亲和矩阵计算中至今仍是优化重点。3.3 谱聚类从图割到特征分解Shi和Malik在2000年的PAMI论文《Normalized Cuts and Image Segmentation》是谱聚类最常被引用的源头之一。他们研究图像分割时发现像素之间的相似度可以用图表示分割问题可以转化为图割问题而最小化归一化割的目标函数可以松弛为求解拉普拉斯矩阵的广义特征值问题。这篇论文把聚类从“距离计算”带到了“谱分解”的层次。Ng、Jordan和Weiss在NIPS 2001的论文则给出了更工程化的谱聚类算法流程构建相似度矩阵S计算归一化拉普拉斯矩阵取前k个特征向量组成新特征矩阵对每一行做归一化最后对行向量做k-means。这里的核心洞察是原始空间里线性不可分的簇在拉普拉斯特征向量构成的空间里往往变得线性可分。实际做谱聚类我建议直接按NJW的版本实现步骤清晰scikit-learn里的SpectralClustering也是这个思路。3.4 子空间聚类应对高维的利器除了前面提到的SSC值得关注的还有Vidal团队后续的工作以及Liu等人在2013年提出的低秩子空间聚类LRR。SSC走稀疏路径LRR走低秩路径两者理论基础都很扎实但计算复杂度都不低处理上万样本会比较吃力。这类方法的亲和矩阵通常用ADMM交替方向乘子法求解对工程实现要求比较高。如果只是想用子空间聚类处理实际问题我建议先跑通scikit-learn提供的谱聚类接口自己构造一个亲和矩阵比如用相关性系数或余弦相似度看看效果再决定要不要上SSC/LRR这种重武器。读完论文是一回事能复现、会用是另一回事这两者之间隔着大量调参和实现细节。4. 工具选型与完整实操4.1 聚类算法到底用什么软件跑热词里有“kmeans聚类算法matlab”“kmeans聚类算法用什么软件”这类搜索说明很多人第一步卡在工具选择上。我的建议很直接新项目优先Python存量项目或教学演示用Matlab没问题但生产环境基本以Python和Scala为主。Python的优势在于生态完整scikit-learn有全套聚类算法SciPy有层次聚类的linkage和dendrogram用matplotlib做可视化配合pandas做数据预处理一条龙搞定。Matlab的优势是矩阵操作直观自带kmeans函数且有绘制聚类图和树状图的便捷API适合教学和快速验证算法原型但部署和团队协作成本相对高。以Python为例跑一个基础k-means只需几行from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler import numpy as np data np.loadtxt(data.csv, delimiter,) scaled StandardScaler().fit_transform(data) model KMeans(n_clusters4, initk-means, n_init10, random_state42) labels model.fit_predict(scaled)注意n_init参数我习惯至少设为10因为k-means对初始化敏感多次随机初始化解里取最优是稳定结果的低成本手段。4.2 层次聚类的Python完整实现层次聚类在Python里主要用的是SciPy的层次聚类模块而不是scikit-learn。原因是SciPy直接提供了linkage、dendrogram和fcluster这些底层接口控制粒度细适合做研究和定制化可视化。from scipy.cluster.hierarchy import linkage, dendrogram, fcluster from scipy.spatial.distance import pdist import matplotlib.pyplot as plt # 计算样本间距离矩阵默认欧氏距离 dist_mat pdist(scaled, metriceuclidean) # 层次聚类method可选single/complete/average/ward Z linkage(dist_mat, methodward) # 画树状图 plt.figure(figsize(12, 6)) dendrogram(Z, truncate_modelevel, p5) plt.show() # 按距离阈值切分出k个簇 labels fcluster(Z, t4, criterionmaxclust)distance metric那里热词里有“欧氏聚类”其实指的就是以欧氏距离为前提的聚类流程。欧氏距离是最常用的选择但要注意它对量纲敏感数据各维度量级差异大时必须先标准化。如果特征是文本或高维稀疏数据用余弦距离更合适如果关心变量间的绝对差而非相对趋势曼哈顿距离也可能更好。距离度量选错后面的算法再精也没用这是聚类实践里的第一性错误。4.3 聚类热图、趋势图与富集条目生物信息学场景热词里“聚类热图趋势图富集条目”明显指向生物信息学中的转录组数据分析这个场景我单独拿出来讲因为它的操作流程和通用聚类不太一样细节很多。聚类热图的标准做法是行为基因列为样本用颜色深浅表示表达量高低同时按聚类结果重排行和列让相似基因和相似样本在图上连成块。Python里最常用的是seaborn的clustermapimport seaborn as sns import pandas as pd expr_df pd.read_csv(expression_data.csv, index_col0) sns.clustermap(expr_df, methodward, metriceuclidean, z_score0, cmapRdBu_r, figsize(10, 8)) plt.show()z_score0表示对每行做z-score标准化这在基因表达热图里几乎是必须的因为基因之间的表达量绝对值差异巨大不看相对变化趋势没法比较。趋势图表达模式趋势图一般按聚类结果把基因分成若干簇每个簇里画所有基因的表达折线并叠加均值趋势线。这样做的好处是能直观看出每个簇对应的生物学过程随时间或处理条件的变化方向。富集条目则是在聚类得到基因簇之后对每个簇做GO或KEGG功能富集分析看看这些共表达的基因是否在某个通路里显著富集。这套流程我踩过最大的坑是聚类数选多少直接决定后续生物学结论。基因表达数据通常聚类成6到12簇但这不是拍脑袋定的应该结合轮廓系数和生物学可解释性综合判断。我曾经按轮廓系数选出的最优k值分出的簇在功能上完全不可解释后来改成“优先保证每个簇都有显著富集条目”反而得到更有价值的结论。技术指标服务于业务解释这个顺序不能颠倒。5. 常见问题与排查技巧实录5.1 k值到底怎么选k值选择是聚类问题里被问得最多的没有之一。常用的技术手段是肘部法则和轮廓系数肘部法则看簇内平方和随k增大的下降曲线找个下降速率放缓的拐点轮廓系数则衡量样本与自身簇的紧密程度和与其他簇的分离程度取值越接近1越好。这俩都不是银弹拐点经常不明显轮廓系数在数据分布不均匀时也会误导。我在实际项目中用的方法很土但很有效先算技术指标缩小候选范围再结合业务含义逐一手动看结果。比如电商用户分群k值取3和取5差异是“是否有必要把高价值用户再拆成流失预警和潜力用户”这个判断只有业务方说了算。另外如果算法本身不需要预设k比如DBSCAN、层次聚类看树状图切分优先考虑这类方法可以少一个拍脑袋的参数。5.2 数据标准化与特征工程聚类算法几乎全部依赖距离度量而距离对量纲极其敏感。拿用户数据举例年龄取值20到60收入取值5000到50000如果直接算欧氏距离收入项会完全主导距离计算年龄维度形同虚设。标准做法是StandardScaler做z-score标准化或者用MinMaxScaler缩放到0到1区间。对于偏态严重的特征先做log变换再标准化往往更合理。还需要警惕高相关特征造成的重复加权。比如同时用了“消费次数”和“消费天数”两个强相关特征相当于把同一个信息维度加权了两次会扭曲距离计算。这种情况建议先做PCA或相关性过滤再进聚类流程。数据预处理的时间应该占整个聚类项目的一半以上这是所有做聚类的人最终都会得出的结论。5.3 聚类结果怎么评估聚类是无监督问题没有标签所以评估天然有争议。大体分两类外部指标有真实标签时和内部指标无标签时。外部指标有ARI调整兰德指数、NMI归一化互信息适合在公开数据集上验证算法效果内部指标有轮廓系数、Davies-Bouldin指数、Calinski-Harabasz指数适合真实业务数据。我的经验是内部指标只能作为参考千万不要唯指标论。轮廓系数高不代表聚类结果有业务洞察轮廓系数低也不代表结果没用。比较可靠的做法是多算法交叉验证同一个数据k-means、层次聚类、DBSCAN各跑一遍如果三种方法的结果高度一致那说明数据里确实存在天然的分组结构结论很可信如果三种结果差异巨大就要回头检查数据预处理、距离度量和参数设置而不是急着选某个算法的输出。5.4 实操中的高发问题速查现象可能原因解决建议k-means每次跑出的结果都不一样随机初始化导致局部最优设置random_state提高n_init使用k-means聚类结果出现超大簇吞掉其他簇数据量纲不平衡或特征冗余标准化特征剔除高相关特征尝试密度聚类DBSCAN结果全是噪声点eps过小或minPts过大用k-dist图选择eps调小minPts层次聚类内存溢出样本量大距离矩阵复杂度O(n²)先抽样跑原型换MiniBatchKMeans改用近似最近邻高维数据聚类效果差距离度量失效维度灾难先降维PCA/UMAP改用子空间聚类或谱聚类聚类结果无法解释特征选择不贴合业务重新梳理特征把聚类数往小调结合业务标签做验证再补一个很多人不知道的小技巧聚类前先做异常值检测。无论哪个聚类算法离群点都会干扰聚类中心或簇的结构。先用IQR规则或Isolation Forest把明显异常点剔掉分完簇再用规则判断这些异常点属于哪个簇比带着噪声硬聚类效果稳定得多。另外做聚类展示时尽量用降维可视化辅助判断但心里要清楚PCA或者UMAP存在信息损失图上看起来重叠的簇在原始空间里可能分得很开图上分得很开的簇在原始空间里也可能只是勉强分开。可视化是沟通工具不是验证工具拿它辅助讲故事没问题拿它当最终评估标准就会翻车。我个人的体会是聚类的难点从来不在算法本身而在于你怎么理解数据、怎么把聚类结果翻译成业务可用的结论。多跑几个算法多和业务方聊几轮比反复调参有用得多。这个领域论文很多但落到实际项目里扎实的预处理、合理的评估、可解释的输出永远是第一位的。
返回列表