资讯动态

K-means、层次聚类与DBSCAN实战对比:基于鸢尾花数据集的聚类算法调参、评估与避坑指南

发布时间:2026/9/27 4:29:38 来源:尧图企业网站定制
聚类算法这块内容我前前后后在不同项目里用过不下十几次从最早的纯手写距离矩阵到后来用sklearn一行调用踩过的坑算是比较全了。这次拿鸢尾花数据集做三种聚类——K-means、层次聚类、密度聚类——看起来像是教科书里的标准练习但真动手做一遍你会发现每种算法在同一个数据集上暴露出来的问题完全不一样而这些差异恰恰是理解聚类本质的最好入口。这篇文章我会把三种算法的完整实操过程拆开讲包括参数怎么定、结果怎么评估、遇到不收敛或者聚类效果差的时候怎么排查适合刚入门机器学习、想搞明白聚类到底怎么回事的朋友也适合已经会调库但说不清楚背后逻辑的人。读完你至少能做到拿到一份没有标签的数据知道该选哪种聚类、参数怎么调、结果怎么判断好坏。1. 三种聚类算法的整体设计思路与选型逻辑1.1 为什么用鸢尾花数据集做聚类练习鸢尾花数据集在机器学习里的地位大概相当于学吉他时的《小星星》——简单、经典、但真弹好也不容易。它一共150个样本4个特征花萼长度、花萼宽度、花瓣长度、花瓣宽度三个类别各50个样本。做分类任务时它有标签做聚类任务时我们把标签藏起来假装不知道有几类让算法自己去找。这个数据集适合做聚类练习有几个原因。第一特征维度低4维可以直接可视化你能亲眼看到聚类结果和真实标签的差异。第二三个类别在特征空间里的分离程度不一样——其中一类Setosa和另外两类分得很开另外两类Versicolor和Virginica有重叠这就制造了一个天然的难度梯度能让你看出不同算法的优劣。第三样本量小跑得快调参迭代的成本低。但要注意一个坑很多人做完聚类发现准确率不高就觉得自己代码写错了其实不是。聚类是无监督任务它给出的簇编号和真实标签的对应关系是随机的评估之前需要先做标签映射。这个后面会详细讲。1.2 K-means、层次聚类、密度聚类的核心差异这三种算法代表了聚类思路的三个方向理解它们的差异比记住API重要得多。K-means是划分式聚类核心思想是先指定要分几个簇K值然后迭代地把每个点分配到最近的簇中心再重新计算簇中心直到中心不再移动。它的假设是簇是球形的、大小差不多、密度均匀。优点是快缺点是K值要预先指定对初始中心敏感对非球形簇无能为力。层次聚类是树形结构分两种方向自底向上凝聚型每个点先自成一簇然后不断合并最近的簇和自顶向下分裂型从一个大簇不断拆分。它不需要预先指定簇数生成一棵树树状图之后你再决定切在哪里。优点是结果直观、不需要指定K缺点是大数据量下计算复杂度高O(n²)以上。密度聚类以DBSCAN为代表的核心思想是簇是密度连通的区域被低密度区域隔开。它不需要指定簇数能发现任意形状的簇还能识别噪声点。缺点是对参数邻域半径eps和最小样本数min_samples敏感密度不均匀的数据集上效果可能不好。用一个生活化的类比K-means像是把一群人按就近原则分成K个小组每组的中心是组长层次聚类像是画一张家族树从个人到家族逐层合并密度聚类像是找人群中的密集聚集区站在人群稀疏的地方就算“噪声”。1.3 实操环境与工具选型环境这块没什么好纠结的Python scikit-learn是标准配置。我用的版本是Python 3.10、scikit-learn 1.3、matplotlib 3.7、numpy 1.24。如果你用Anaconda这些基本都自带了。pip install scikit-learn matplotlib numpy pandas scipy选sklearn的理由很简单三种聚类算法它都封装好了API风格统一评估指标也齐全。层次聚类底层依赖scipy的层次聚类模块sklearn做了封装用起来更方便。可视化用matplotlib配合PCA降维把4维数据画到2维平面上。注意不要一上来就装最新版本sklearn不同版本之间某些参数的默认值和行为有变化比如DBSCAN的algorithm参数默认值在0.22版本后改过。建议固定一个稳定版本避免复现时出现莫名其妙的差异。2. 数据准备与特征工程的关键细节2.1 数据加载与初步探查加载鸢尾花数据集有两种方式一种是从sklearn自带的datasets里直接load另一种是从UCI仓库下载CSV。练习用前者就够了但实际项目中你拿到的都是CSV所以我建议两种都走一遍。from sklearn.datasets import load_iris import pandas as pd import numpy as np iris load_iris() X iris.data # 150 x 4 y_true iris.target # 真实标签聚类时不用评估时用 feature_names iris.feature_names df pd.DataFrame(X, columnsfeature_names) print(df.describe()) print(df.head())先看describe的输出重点关注每个特征的均值和标准差。鸢尾花四个特征的量纲其实差不多都是厘米级别所以标准化不是必须的但做了也没坏处。我实测下来标准化之后K-means的收敛速度会快一点因为欧氏距离对量纲敏感。from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_scaled scaler.fit_transform(X)这里有个细节标准化之后数据变成了均值0、方差1的分布如果你后面要解释簇中心的实际含义比如“这个簇的平均花瓣长度是5.2厘米”就需要把中心逆变换回去。我一般会保留scaler对象方便后面inverse_transform。2.2 特征相关性分析与降维可视化4个特征之间是有相关性的花瓣长度和花瓣宽度高度正相关花萼长度和花瓣长度也有一定相关性。做聚类之前看一眼相关性矩阵能帮你判断哪些特征是冗余的。import matplotlib.pyplot as plt import seaborn as sns corr df.corr() sns.heatmap(corr, annotTrue, cmapcoolwarm) plt.title(Feature Correlation) plt.show()从相关性矩阵能看到花瓣长度和花瓣宽度的相关系数在0.96左右几乎可以说是线性关系。这意味着这两个特征提供的信息高度重叠理论上可以去掉一个。但聚类练习里我建议保留全部特征因为我们要观察算法在高维相对而言空间里的表现。为了可视化需要用PCA把4维降到2维。注意PCA是无监督降维它找的是方差最大的方向和聚类结果无关所以用它来可视化聚类结果是合理的。from sklearn.decomposition import PCA pca PCA(n_components2) X_pca pca.fit_transform(X_scaled) print(fExplained variance ratio: {pca.explained_variance_ratio_})我跑出来的解释方差比大概是0.73和0.23加起来0.96说明2维已经保留了绝大部分信息可视化是可信的。如果这个值低于0.8你就要小心了降维后的图可能严重失真不能直接用来判断聚类好坏。2.3 聚类前的数据检查清单动手聚类之前有几个检查项我每次都会过一遍缺失值鸢尾花数据集没有缺失值但实际数据一定要检查。df.isnull().sum()一行搞定。异常值用箱线图或者IQR方法看一遍。鸢尾花里Setosa的花瓣宽度明显偏小但那是真实差异不是异常。重复值df.duplicated().sum()鸢尾花有1个重复样本影响不大但大数据集里重复值会扭曲密度聚类的密度估计。量纲一致性前面说了标准化一下更稳妥。样本量密度聚类对样本量有一定要求样本太少密度估计不可靠。150个样本做DBSCAN是够的但如果你只有几十个样本DBSCAN可能把大部分点都判成噪声。实操心得我习惯在聚类前把数据存一份原始副本因为标准化、降维这些操作会改变数据后面评估或者画图时经常需要回到原始尺度。这个习惯帮我省过好几次重新加载数据的时间。3. K-means算法实操与调参全流程3.1 K-means的核心原理与迭代过程K-means的算法流程可以拆成四步随机选K个点作为初始簇中心。把每个样本分配到距离最近的簇中心。重新计算每个簇的中心该簇所有点的均值。重复2和3直到簇中心不再变化或达到最大迭代次数。它的目标函数是簇内平方和WCSSWithin-Cluster Sum of Squares也叫惯性inertia$$WCSS \sum_{i1}^{K} \sum_{x \in C_i} ||x - \mu_i||^2$$其中$\mu_i$是第i个簇的中心。K-means就是在最小化这个值。但要注意这个优化问题是NP难的K-means用的是贪心迭代只能保证收敛到局部最优不保证全局最优。这就是为什么它对初始中心敏感。sklearn的KMeans默认用k-means初始化这个策略不是随机选点而是让初始中心尽量分散能显著改善收敛结果。我强烈建议保留这个默认值除非你有特殊理由。3.2 K值怎么选肘部法与轮廓系数K值选择是K-means最大的痛点。理论上你可以试遍所有可能的K但怎么判断哪个K最好常用的有两种方法。肘部法Elbow Method画出不同K值对应的inertia找曲线拐点。拐点之后inertia下降变缓说明增加K带来的收益递减。from sklearn.cluster import KMeans inertias [] K_range range(1, 11) for k in K_range: km KMeans(n_clustersk, initk-means, n_init10, random_state42) km.fit(X_scaled) inertias.append(km.inertia_) plt.plot(K_range, inertias, bo-) plt.xlabel(K) plt.ylabel(Inertia) plt.title(Elbow Method) plt.show()鸢尾花数据上inertia在K3之后下降明显变缓肘部在3附近和真实类别数一致。但肘部法有个问题拐点有时候不明显尤其是数据本身没有明显簇结构的时候。轮廓系数Silhouette Score衡量每个点与自身簇的紧密度和与最近簇的分离度取值-1到1越大越好。from sklearn.metrics import silhouette_score sil_scores [] for k in range(2, 11): km KMeans(n_clustersk, n_init10, random_state42) labels km.fit_predict(X_scaled) sil_scores.append(silhouette_score(X_scaled, labels)) plt.plot(range(2, 11), sil_scores, ro-) plt.xlabel(K) plt.ylabel(Silhouette Score) plt.show()我实测鸢尾花上K2的轮廓系数最高因为Setosa和另外两类分得很开分成2簇最“干净”K3次之。这就引出一个重要认知轮廓系数最高的K不一定是你想要的K。如果你知道业务上应该分3类那就选3评估指标只是参考。注意n_init参数控制用不同初始中心跑几次取最好的结果。sklearn 1.4版本之前默认是10之后改成auto。我一般显式设成10保证结果稳定。random_state也要固定否则每次跑出来的簇编号都不一样。3.3 K-means完整实现与结果可视化km_final KMeans(n_clusters3, initk-means, n_init10, max_iter300, random_state42) km_labels km_final.fit_predict(X_scaled) # 可视化 plt.figure(figsize(8, 6)) scatter plt.scatter(X_pca[:, 0], X_pca[:, 1], ckm_labels, cmapviridis, s50, alpha0.7) plt.scatter(pca.transform(km_final.cluster_centers_)[:, 0], pca.transform(km_final.cluster_centers_)[:, 1], cred, markerX, s200, edgecolorsblack, labelCentroids) plt.xlabel(PC1) plt.ylabel(PC2) plt.title(K-means Clustering (K3)) plt.legend() plt.colorbar(scatter) plt.show()从图上能看到K-means把Setosa那一簇分得很准但Versicolor和Virginica的边界上有一些点被分错了。这是意料之中的因为这两类在特征空间里本来就有重叠。簇中心在原始尺度下的值可以这样还原centers_original scaler.inverse_transform(km_final.cluster_centers_) centers_df pd.DataFrame(centers_original, columnsfeature_names) print(centers_df)这样你就能解释每个簇的实际含义了比如“簇0的平均花瓣长度是1.46厘米对应Setosa”。3.4 K-means的评估与标签映射聚类结果和真实标签的对应关系是随机的评估前要做标签映射。最简单的方法是用匈牙利算法找最优匹配from scipy.optimize import linear_sum_assignment from sklearn.metrics import confusion_matrix, accuracy_score def map_labels(y_true, y_pred): cm confusion_matrix(y_true, y_pred) row_ind, col_ind linear_sum_assignment(-cm) mapping {col: row for row, col in zip(row_ind, col_ind)} return np.array([mapping[label] for label in y_pred]) mapped_labels map_labels(y_true, km_labels) print(fAccuracy: {accuracy_score(y_true, mapped_labels):.4f}) print(confusion_matrix(y_true, mapped_labels))我跑出来的准确率大概在0.89左右混淆矩阵显示Setosa全部正确Versicolor和Virginica各有几个错分。这个结果对K-means来说算正常。除了准确率还应该看调整兰德指数ARI和标准化互信息NMI这两个指标不需要标签映射直接衡量两个划分的相似度from sklearn.metrics import adjusted_rand_score, normalized_mutual_info_score print(fARI: {adjusted_rand_score(y_true, km_labels):.4f}) print(fNMI: {normalized_mutual_info_score(y_true, km_labels):.4f})ARI和NMI都在0.7以上说明聚类结构和真实类别有较强的一致性。4. 层次聚类的实操与树状图解读4.1 层次聚类的两种方向与链接准则层次聚类分凝聚型AGNES和分裂型DIANA实践中凝聚型用得更多sklearn的AgglomerativeClustering就是凝聚型。凝聚型的核心是“链接准则”也就是怎么衡量两个簇之间的距离。常用的有四种链接准则距离定义特点单链接single两簇最近点之间的距离能发现长条形簇但对噪声敏感容易产生链式效应全链接complete两簇最远点之间的距离倾向于产生紧凑的等大小簇对噪声不敏感平均链接average两簇所有点对距离的平均折中方案比较稳健Ward合并后簇内方差增量最小倾向于产生等大小球形簇和K-means类似Ward准则在欧氏距离下表现通常最好也是sklearn的默认值。我实测鸢尾花上Ward和average的结果都不错single的结果明显差一些因为链式效应把两个重叠的类合并了。4.2 树状图的绘制与切割层次聚类最直观的输出是树状图dendrogram用scipy画from scipy.cluster.hierarchy import dendrogram, linkage import matplotlib.pyplot as plt Z linkage(X_scaled, methodward) plt.figure(figsize(12, 6)) dendrogram(Z, truncate_modelastp, p30, leaf_rotation90, leaf_font_size10) plt.title(Hierarchical Clustering Dendrogram (Ward)) plt.xlabel(Sample index or cluster size) plt.ylabel(Distance) plt.axhline(y10, colorr, linestyle--, labelCut at distance10) plt.legend() plt.show()树状图的纵轴是合并时的距离横轴是样本。你从下往上看每个叶子是一个样本越往上合并的簇越大。切割树状图就是在某个高度画一条水平线线以下的每个分支就是一个簇。怎么决定切在哪里看纵轴上最大的跳跃。如果某两个合并之间的距离明显大于其他那就在那个高度切。鸢尾花上Ward方法在距离10左右有一个明显跳跃切下去正好得到3个簇。from sklearn.cluster import AgglomerativeClustering hc AgglomerativeClustering(n_clusters3, linkageward) hc_labels hc.fit_predict(X_scaled) mapped_hc map_labels(y_true, hc_labels) print(fHC Accuracy: {accuracy_score(y_true, mapped_hc):.4f}) print(fHC ARI: {adjusted_rand_score(y_true, hc_labels):.4f})层次聚类在鸢尾花上的准确率通常和K-means差不多有时候略高一点因为Ward准则对球形簇的假设和K-means类似但不需要随机初始化结果更稳定。4.3 距离阈值与簇数量的自动确定如果你不想预先指定簇数可以用距离阈值来切hc_dist AgglomerativeClustering(n_clustersNone, distance_threshold10, linkageward) hc_dist_labels hc_dist.fit_predict(X_scaled) print(fNumber of clusters: {len(set(hc_dist_labels))})distance_threshold的选择需要结合树状图看。设得太小会产生很多小簇设得太大所有点合并成一簇。我一般先画树状图找到明显跳跃的位置把阈值设在跳跃点附近。实操心得层次聚类的计算复杂度是O(n²log n)Ward到O(n³)某些链接准则样本量超过几千就不太适合了。如果数据量大可以先做一次K-means粗聚类再对簇中心做层次聚类这样能把复杂度降下来。这个技巧在实际项目里很实用。5. 密度聚类DBSCAN的实操与参数调优5.1 DBSCAN的核心概念eps与min_samplesDBSCAN有两个核心参数eps邻域半径。以某个点为中心eps为半径的圆内的区域就是它的邻域。min_samples成为核心点所需的最小邻域点数包括自己。基于这两个参数点被分成三类核心点邻域内至少有min_samples个点。边界点本身不是核心点但在某个核心点的邻域内。噪声点既不是核心点也不是边界点。簇的定义是从某个核心点出发所有密度可达的点构成一个簇。密度可达的意思是存在一条路径路径上相邻的点都在彼此的eps邻域内。DBSCAN的优点是不需要指定簇数、能发现任意形状的簇、能识别噪声。缺点是对参数敏感尤其是eps差一点点结果就天差地别。5.2 k-距离图确定eps的合理范围eps怎么定常用的方法是k-距离图。对每个点计算它到第k个最近邻的距离k一般取min_samples把这些距离从小到大排序画出来找曲线的“肘部”。from sklearn.neighbors import NearestNeighbors min_samples 5 nbrs NearestNeighbors(n_neighborsmin_samples).fit(X_scaled) distances, indices nbrs.kneighbors(X_scaled) k_distances np.sort(distances[:, -1]) plt.plot(k_distances) plt.xlabel(Points sorted by distance) plt.ylabel(f{min_samples}-th Nearest Neighbor Distance) plt.title(k-distance Graph) plt.grid(True) plt.show()鸢尾花标准化后的数据k-距离图在0.8到1.2之间有一个明显的拐点所以eps设在这个范围比较合理。我试了0.8、1.0、1.2三个值1.0左右的结果最稳定。from sklearn.cluster import DBSCAN db DBSCAN(eps1.0, min_samples5) db_labels db.fit_predict(X_scaled) n_clusters len(set(db_labels)) - (1 if -1 in db_labels else 0) n_noise list(db_labels).count(-1) print(fClusters: {n_clusters}, Noise points: {n_noise})我跑出来是2个簇加几个噪声点。为什么不是3个因为Versicolor和Virginica在密度上是连通的DBSCAN把它们合并成了一个簇。这不是bug是DBSCAN的特性——它按密度连通性定义簇不按“应该有几类”来分。5.3 min_samples的选择与噪声点处理min_samples的选择有个经验法则min_samples 维度 1对于4维数据至少取5。取大一点能减少噪声点的数量但可能把一些小簇也当成噪声。取小一点能发现更多簇但噪声点会增多。for ms in [3, 5, 8, 10]: db DBSCAN(eps1.0, min_samplesms) labels db.fit_predict(X_scaled) n_c len(set(labels)) - (1 if -1 in labels else 0) n_n list(labels).count(-1) print(fmin_samples{ms}: clusters{n_c}, noise{n_n})我实测下来min_samples5是个比较平衡的值。min_samples3时噪声点少但簇比较碎min_samples10时噪声点明显增多。噪声点的处理要看业务场景。如果噪声点是数据采集错误直接剔除如果噪声点本身有业务含义比如异常用户那就单独分析。聚类练习里我一般先把噪声点标出来看看它们在特征空间里的位置判断是真实的异常还是参数设置不当造成的。5.4 DBSCAN结果可视化与评估plt.figure(figsize(8, 6)) unique_labels set(db_labels) colors [plt.cm.Spectral(each) for each in np.linspace(0, 1, len(unique_labels))] for k, col in zip(unique_labels, colors): if k -1: col [0, 0, 0, 1] # 噪声点用黑色 class_member_mask (db_labels k) xy X_pca[class_member_mask] plt.scatter(xy[:, 0], xy[:, 1], c[col], s50, alpha0.7, labelfCluster {k} if k ! -1 else Noise) plt.xlabel(PC1) plt.ylabel(PC2) plt.title(DBSCAN Clustering) plt.legend() plt.show()评估DBSCAN时要注意噪声点标签-1不能直接参与ARI和NMI的计算需要先剔除mask db_labels ! -1 if len(set(db_labels[mask])) 1: print(fDBSCAN ARI: {adjusted_rand_score(y_true[mask], db_labels[mask]):.4f}) print(fDBSCAN NMI: {normalized_mutual_info_score(y_true[mask], db_labels[mask]):.4f})因为DBSCAN把两个类合并了ARI和NMI会比K-means低一些但这不代表DBSCAN“差”只是它的簇定义和真实类别不一致。6. 三种算法的对比分析与常见问题排查6.1 同一数据集上的结果对比把三种算法的结果放在一起对比能看出很多门道。我整理了一个对比表维度K-means层次聚类WardDBSCAN需要预设簇数是否可切树状图否簇形状假设球形球形Ward任意形状对噪声敏感度高中低能识别噪声鸢尾花上的簇数332噪声准确率映射后~0.89~0.90不适用簇数不匹配ARI~0.73~0.75~0.55剔除噪声后计算复杂度O(nKt)O(n²log n)O(n log n)结果稳定性依赖初始化确定性强依赖参数从表里能看出没有哪个算法全面占优。K-means快但需要预设K层次聚类稳定但慢DBSCAN灵活但参数难调。6.2 常见问题速查表实操中遇到的问题我整理成了速查表问题现象可能原因解决方法K-means每次结果不一样未固定random_state或n_init太小设random_state42n_init10K-means准确率很低未标准化或K值选错标准化数据用肘部法轮廓系数选K层次聚类树状图看不清样本太多叶子重叠用truncate_modelastp截断显示DBSCAN全是噪声eps太小或min_samples太大用k-距离图重新定eps降低min_samplesDBSCAN只有一个簇eps太大或min_samples太小减小eps增大min_samples轮廓系数为负样本被分到了错误的簇检查K值或换用其他算法ARI很低但可视化看着还行簇编号和标签未映射用匈牙利算法做标签映射后再算准确率6.3 独家避坑技巧与经验总结几个我在实际项目里踩过的坑分享出来帮你省时间第一不要迷信单一评估指标。轮廓系数、ARI、NMI各有侧重我一般三个都看再结合可视化。有一次一个项目轮廓系数0.6看着不错但可视化发现簇的形状很怪后来换了DBSCAN才解决。第二标准化不是万能的。如果特征本身有明确的物理意义且量纲一致不标准化反而能保留原始的距离关系。鸢尾花就是这种情况我两种都试过结果差异不大。第三DBSCAN的eps不要用默认值。sklearn的默认eps0.5在标准化数据上通常偏小会导致大量噪声点。一定要用k-距离图重新定。第四层次聚类的linkage选择要看数据。Ward适合球形簇average适合一般情况single适合长条形簇但容易链式效应。不确定的时候先画树状图看看。第五聚类结果的解释比算法本身更重要。老板不会关心你用了什么算法他关心的是“这三个簇分别代表什么”。所以聚类完之后一定要回到原始特征去解释每个簇的含义比如“簇0是花瓣小的品种簇1是花瓣中等但花萼长的品种”。提示如果数据量超过1万K-means是唯一现实的选择层次聚类和DBSCAN都会很慢。这时候可以用MiniBatchKMeans它是K-means的在线版本速度快很多精度损失很小。7. 聚类效果的进阶优化与扩展方向7.1 用PCA降维后再聚类前面我们用PCA只是为了可视化其实PCA也可以作为聚类的前置步骤。降维之后噪声减少聚类效果可能更好。但要注意PCA是无监督的它保留的是方差最大的方向不一定对聚类最有利。pca_2d PCA(n_components2) X_pca_2d pca_2d.fit_transform(X_scaled) km_pca KMeans(n_clusters3, n_init10, random_state42) labels_pca km_pca.fit_predict(X_pca_2d) print(fARI after PCA: {adjusted_rand_score(y_true, labels_pca):.4f})我实测下来降到2维后ARI反而略降了一点因为丢掉的两个维度里还是有一些区分信息的。所以PCA降维聚类要谨慎除非原始维度很高比如上百维否则不一定要降。7.2 用GMM做软聚类K-means是硬聚类每个点只属于一个簇。高斯混合模型GMM是软聚类给出每个点属于每个簇的概率。如果簇之间有重叠GMM往往比K-means更合适。from sklearn.mixture import GaussianMixture gmm GaussianMixture(n_components3, covariance_typefull, random_state42) gmm_labels gmm.fit_predict(X_scaled) gmm_proba gmm.predict_proba(X_scaled) print(fGMM ARI: {adjusted_rand_score(y_true, gmm_labels):.4f})GMM在鸢尾花上的ARI通常和K-means接近但它能告诉你“这个点有70%概率属于簇130%属于簇2”这个信息在很多场景下很有用。7.3 聚类结果的业务落地思路聚类做完不是终点怎么用才是关键。几个常见的落地思路客户分群把用户按行为特征聚类每个簇代表一类用户针对性做运营。异常检测DBSCAN的噪声点就是天然的异常候选可以进一步排查。数据压缩用簇中心代表整个簇减少数据量。特征工程把簇标签作为一个新特征喂给下游的分类或回归模型。我在一个用户行为分析项目里先用K-means把用户分成5群然后把簇标签作为特征加入流失预测模型AUC提升了3个点。这个思路在很多场景下都管用。最后分享一个我常用的技巧聚类完之后把每个簇的样本数、各特征均值、与整体均值的差异整理成一张表这样一眼就能看出每个簇的特点。这个表比任何可视化都直观汇报的时候特别好用。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑