K-Means用户分群实战:从订单表到精细化运营全流程
如果你手里有一张几百万行的订单表老板突然让你把用户分成几个小组方便做精细化运营你的第一反应是什么我见过不少新人的做法是拉一个消费金额排名然后自己定三个阈值超过5000的叫高价值500到5000的叫中等低于500的叫低价值。这样做不能说完全没用但稍微推敲一下就发现问题了只按金额分一个每个月固定买几百块的常客和一个一年前一次性买了2000块就再也没回来的用户会被丢进同一个组里但这两个人对运营策略的需求完全不同。这个场景正是 K-Means 聚类最经典的应用舞台之一——用用户行为数据做市场细分。这篇不聊理论直接从一张原始订单表出发走完特征构造、数据预处理、K值选择、聚类训练、结果解读、画像落地和运营策略的全流程。适合正在做数据分析、用户增长、精细化运营的朋友也适合想学无监督学习但一直卡在“不知道算法怎么用到业务里”的机器学习入门者。看完你就能照着这套流程自己跑出一个能用、能讲、能落地的用户分群模型。1. 先想清楚为什么市场细分优先选K-Means1.1 从“拍脑袋分层”到“数据驱动分群”的转变很多人做用户分层第一反应是用 RFM 模型手动打分。RRecency最近一次购买距今几天FFrequency购买次数MMonetary消费金额然后每个维度按三分位或经验阈值切成高、中、低三档。这样做在数据量小、业务简单的时候确实能跑但实际操作中你会遇到三个绕不开的痛点。第一个痛点是阈值根本没法定。不同业务、不同周期、不同品类用户的购买间隔和金额分布天差地别。上个月用的阈值这个月大促一冲整个分布都平移了老阈值立刻失效。第二个痛点是维度组合爆炸。RFM 三档三分是 8 种组合你勉强能一个个想运营策略一旦你加入品类偏好、折扣敏感度、活跃时长这些行为特征手工规则连枚举都枚举不完。第三个痛点是规则无法回答“谁离谁更近”这类问题。比如两个用户A 的 R2 天、F8 次、M600 元B 的 R10 天、F5 次、M900 元这两个人到底谁更像高价值人群手工规则只能告诉你“A 活跃”、“B 金额高”但按什么权重合并这三个维度完全靠拍脑袋。K-Means 解决的正是这个问题。它把用户的所有行为特征看成高维空间里的坐标用距离度量相似性。距离近的用户行为模式天然接近不需要人肉设定阈值也不需要预先定义什么叫“高价值”。分群结果由数据自己说话你只需要在事后给每个簇赋予业务含义。这正是无监督学习在用户分析里最舒服的位置发现你没想到的群体结构。1.2 一次完整的细分项目要走过哪些环节市场细分听起来是个建模问题但实际跑下来你会发现算法训练只占整个项目不到三分之一的精力。一个能落地的细分项目完整链条是这样的第一步业务理解。先和运营、增长的同事聊清楚分群给谁看用来做什么决策是识别高价值客户做重点维护还是找出沉睡用户做召回还是给不同人群设计不同的推荐策略目标不同后续选特征的方向完全不同。第二步数据提取。把订单表、用户基础信息、行为日志按用户粒度聚合。第三步特征工程。构造能反映用户行为差异的特征通常以 RFM 为骨架再补一些业务相关的行为特征。第四步预处理。处理缺失值、异常值、偏态分布做标准化。第五步聚类建模。定 K 值、训练 K-Means、评估聚类质量。第六步结果解读。读聚类中心、画画像、给每个群命名。第七步策略设计。把分群结果交给业务方输出用户 ID 和群标签的映射表并设计差异化的运营动作。第八步效果评估。过一段时间回头看每个群的关键指标变好还是变坏验证细分是否真的有用。这八步里最容易被新手跳过的是第一步和第八步。很多人拿到数据就开跑聚类跑出来一堆统计上很漂亮、业务上不知道说什么的簇最后沦为报告里的一张彩图。所以这篇文章虽然叫“实战”你也要记住算法只是手段把分群变成运营动作才是目的。2. 动手前先备料用户行为特征怎么构造2.1 原始数据常见结构和取数逻辑为了讲得具体点我拿一个典型的电商场景举例。假设你所在的某平台有一张订单表核心字段长这样user_id用户 ID、order_id订单 ID、order_time下单时间、pay_amount实付金额、category商品类目、discount_amount优惠金额。有些人可能还会拿到用户行为日志包含 browse_time浏览时长、cart_count加购次数、favorite_count收藏次数这些字段。数据当然是越丰富越好但你要清楚一点做第一次细分迭代时不一定要把所有表都搬出来先把订单表用透拿到第一版结果再说。这个“最小可用数据集”的思路能帮你快速跑通流程避免陷在取数里出不来。取数逻辑上建议以用户 ID 为粒度把行为数据聚合到“每个用户在过去某个统计周期内做了什么”的一行记录。这里有个很容易犯的错误统计周期不统一。比如有人用“最近一年”的数据算频次和金额有人用“最近三个月”的最后合进一个表里特征口径乱了聚类结果自然乱七八糟。我建议起步阶段先统一用一个窗口比如近 90 天加近 180 天两个窗口并行后面的特征工程会很灵活。2.2 从RFM到行为特征特征清单参考RFM 是用户行为特征的基础骨架这点永远不会过时。我在实际项目中通常这样构造Recency以数据快照日期一般取订单表最大日期加一天为基准减去每个用户最近一次下单的日期取天数间隔。间隔越小用户越活跃。Frequency统计周期内用户的下单次数。注意这里可以用多个窗口比如近 30 天次数、近 90 天次数。为什么分窗口因为“最近 30 天买了 3 次”和“最近一年买了 3 次”是完全两种用户前一个可能是活跃用户后一个可能是低频长尾用户混在一起算一个特征会丢失时间维度上的差异。Monetary统计周期内的实付金额总和。这个特征通常不会直接用原值因为金额分布右偏严重后面预处理阶段要做变换。在 RFM 基础上我会根据业务场景再补几个行为特征。下面这个表格是我在电商类项目里常用的一套特征清单你可以按自己的数据情况增删特征名计算口径业务含义平均客单价实付金额总和 / 下单次数用户单次消费能力类目覆盖数不同商品类目数量用户需求广度折扣敏感度优惠金额 / 商品原价总金额用户对价格的敏感程度最近一次浏览距今快照日期 - 最后一次浏览日期用户当前活跃状态加购转化率加购次数 / 浏览次数用户购买意向强度夜间下单占比晚上22点后订单数 / 总订单数下单时段偏好需要提醒一句特征不是越多越好。K-Means 在高维空间里计算欧氏距离时特征越多各维度贡献越容易被稀释而且太多特征会让后续给分群“起名字”变得困难。一般来说8 到 15 个标准化数值特征已经足够支撑大多数细分项目。多于 20 个特征时我建议先做一轮相关性检查和筛选。2.3 数据预处理标准化、异常值和缺失值特征凑齐了还不能直接扔给 K-Means。预处理做不好后面模型再漂亮也是白搭。第一关是缺失值。比如有些用户没有浏览记录行为日志相关的特征就是空值。处理方式很简单你决定不了的口径找业务方确认比如“没有浏览记录”到底代表“来了没浏览”还是“根本没来”这两种情况填 0 的含义完全不同。如果是 RFM 这类硬特征缺失说明数据质量问题需要回溯取数逻辑。第二关是异常值。金额、频次这类特征天然右偏总有那么几个用户一个月买几十单单笔金额巨大。K-Means 对极端值非常敏感因为它是基于距离的一个离群点可能把整个聚类中心拽过去。我的做法是先看分位数把超过 99 分位的值做截尾Winsorize也就是超过上限的值一律替换成上限值。注意不是说这些用户不重要只是让他们不要扭曲聚类结构你可以在分群后单独把他们的名单拉出来做重点客户分析。第三关是分布变换。金额、频次这类长尾特征即使标准化之后依然严重偏态欧氏距离还是会过度受大值影响。实操中我习惯先对这类特征做对数变换再标准化。量化一下一个用户月消费 12000 元另一个 500 元原始值差 24 倍取 log 之后差距缩小到 2 倍左右这样聚类时不会被金额极值牵着鼻子走。第四关才是标准化。为什么必须标准化举个例子Frequency 取值可能只有个位数Monetary 取值可能是几千如果不做处理欧氏距离几乎完全由金额决定购买次数这个维度的信息直接被淹没。标准化最常用的是 Z-score也就是每个特征减去均值除以标准差让所有特征都在同一量纲下比较。Min-Max 归一化也有用但更适合特征本身有明确上下界且没有极端值的情况。我日常默认 Z-score简单可靠。import pandas as pd import numpy as np # 假设订单表 df_order 有 user_id, order_time, pay_amount, discount_amount, category snapshot_date df_order[order_time].max() pd.Timedelta(days1) rfm df_order.groupby(user_id).agg( recency(order_time, lambda x: (snapshot_date - x.max()).days), frequency(order_time, count), monetary(pay_amount, sum), discount_ratio(discount_amount, lambda x: x.sum() / df_order.loc[x.index, pay_amount].sum()) ).reset_index() # 对数变换右偏特征 rfm[monetary_log] np.log1p(rfm[monetary]) rfm[frequency_log] np.log1p(rfm[frequency]) # Z-score 标准化 from sklearn.preprocessing import StandardScaler feature_cols [recency, frequency_log, monetary_log, discount_ratio] scaler StandardScaler() X_scaled scaler.fit_transform(rfm[feature_cols])你自己跑的时候注意groupby和聚合函数里牵扯到金额时一定要确认“实付金额”的口径是用户实际掏了多少钱不含优惠券、不含退款。很多项目从这里开始口径就乱了后面全盘皆输。3. 建模实战从肘部法则到聚类结果评估3.1 特征相关性检查与降维取舍进入建模之前我强烈建议先看一眼特征之间的相关矩阵尤其是都在衡量“活跃程度”的特征。比如 Frequency 和 Monetary 往往高度相关因为买得多的人总金额也高这在业务上是符合直觉的但对聚类来说却意味着信息冗余两个特征其实在重复表达同一件事会让对应维度在距离计算里被隐性加权。我看过一个案例某分析团队把近 30 天、60 天、90 天、180 天四个窗口的购买次数全部放进去做聚类结果就是频率类特征在聚类里权重过高用户分群几乎只按频次区分金额和品类偏好全被淹没了。排查到最后就是相关系数矩阵里一堆 0.9 以上的强相关对。处理方式有两种一是删减保留最有业务解释力的那个比如只留近 90 天的购买频次二是合并用比值或差值构造新特征比如近 30 天频次 / 近 90 天频次表达“近期活跃度占比”。我更喜欢第二种因为新特征往往更有业务洞察力。降维的问题也常被问到。很多人习惯跑个 PCA把十几个特征压到两三个主成分再聚类理由是“降维了更稳定”。这个做法我一般不推荐直接用在建模输入上。PCA 得到的主成分是特征的线性组合它的维度在业务上很难解释你最后给运营负责人讲“这群用户在第 2 主成分上得分高”对方大概率一脸茫然。但 PCA 有个很好的用途是可视化验证把高维特征压到二维看聚类结果在二维平面上是否真的分得开这个角色我后面会再提。3.2 K值怎么定别只盯着一张图K-Means 需要提前指定簇数 K这是无监督模型里最让人纠结的参数。我的建议是用“指标辅助 业务判断”组合拳而不要只看单一指标。第一个常用指标是肘部法则。K-Means 每次聚类都可以得到一个簇内平方和inertia也叫簇内误差它衡量的是所有样本到各自簇中心的距离平方之和。K 越大每个簇越紧凑inertia 必然越小但超过某一个点后会下降得越来越慢形成一个“肘部”。实际操作中我画一张 K 从 2 到 10 的 inertia 曲线找下降趋势从陡峭变平缓的那个拐点。from sklearn.cluster import KMeans inertia_values [] K_range range(2, 11) for k in K_range: km KMeans(n_clustersk, initk-means, n_init10, random_state42) km.fit(X_scaled) inertia_values.append(km.inertia_)这里有个细节inertia 曲线很多时候没有特别明显的“肘”只看到一条平滑下降的弧线。这时候第二个指标就派上用场了——轮廓系数。轮廓系数综合了簇内紧密程度和簇间分离程度每个样本的轮廓分数是 (b - a) / max(a, b)其中 a 是样本到同簇其他样本的平均距离b 是样本到最近其他簇所有样本的平均距离。所有样本的平均值就是整体轮廓分数取值范围在 -1 到 1 之间越接近 1 说明簇越紧凑、簇间越分离。from sklearn.metrics import silhouette_score sil_scores [] for k in K_range: km KMeans(n_clustersk, initk-means, n_init10, random_state42) labels km.fit_predict(X_scaled) sil_scores.append(silhouette_score(X_scaled, labels))经验上轮廓系数在 0.3 以上就说明数据有可识别的聚类结构0.5 以上是相当清晰的分群。但真实业务数据很少给你 0.6 以上的分数所以别死磕这个数。我的核心建议是指标只是参考最终 K 值要由“业务能不能讲清楚”决定。举个例子某次项目里肘部法和轮廓系数都指向 K7但把 7 个簇的中心表拉出来一看其中两个簇在 R 和 M 上几乎一样只是频率差了 0.5 次运营根本没办法针对它们设计不同策略。后来砍到 5 个簇每个簇特征差异鲜明运营能直接给出不同的触达方案。反过来也有过 K3 时高价值人群全挤在一个簇里没法再细化提升到 K5 后才把“高价值成熟客户”和“高价值潜力客户”区分开。所以我的标准流程是先看指标圈出 2 到 3 个候选 K再逐个检查聚类中心的业务可解释性最后拍板。3.3 训练K-Means的参数细节与代码实现K 值确定后训练本身很简单但几个参数值得你花半分钟理解一下。km KMeans( n_clusters5, initk-means, n_init10, max_iter300, tol1e-4, random_state42 ) km.fit(X_scaled) # 给每个用户打上簇标签 rfm[cluster] km.labels_init 参数我默认用 k-means。K-Means 初始时是随机挑簇中心的如果初始中心选得不好很容易陷入局部最优。k-means 的思路是让初始中心互相隔得尽量远能显著提升最终聚类质量。n_init 表示用多少组不同的初始中心跑多轮最终选 inertia 最小的那一组一般设 10 就够了。max_iter 是每轮迭代的上限tol 是收敛阈值保持默认即可。random_state 必须固定否则你每次跑出来的簇标签顺序都是随机的排查问题时你会疯的。还有一个细节容易忽视sklearn 里 KMeans 的 labels_ 顺序是 0 到 K-1但注意它不保证标签编号对应任何业务含义。比如编号为 0 的簇不一定是“高价值客户”可能只是“低频沉睡用户”。所以训练完成后务必按簇中心或特征均值排序给簇重新编号并命名。我习惯的做法是直接按km.cluster_centers_的某个核心业务列排序比如按标准化后的金额中心降序排列让 0 号簇永远是金额贡献最高的群。聚类中心是标准化空间里的坐标直接看会有点反直觉。我通常在建模后用两种方式还原一是scaler.inverse_transform把中心逆变换回原始量纲二是直接对原始表按cluster分组算中位数或均值。第一种快第二种更稳还能顺带看每个簇的分位数我更喜欢第二种。# 按簇分组看原始特征的描述统计 rfm_grouped rfm.groupby(cluster)[[recency, frequency, monetary, discount_ratio]].median()如果这个群组的 Recency 中位数只有 6 天Frequency 中位数 7 次Monetary 中位数 800 元Discount_ratio 中位数 0.08你再结合全体均值一对比这个群的画像就立体起来了。聚类中心本身不是让你盯着看的而是用来“读差异”的。训练完成后还有一步很多人会漏掉聚类质量的多指标交叉验证。除了轮廓系数我还会顺手看 Davies-Bouldin Index越小越好和 Calinski-Harabasz Index越大越好。不用特别理解它们的数学细节只要知道它们是衡量“簇内紧密、簇间分离”的替代指标用来交叉确认轮廓系数的判断没有受单一指标的偏置影响就够了。4. 解读聚类结果给每个用户群一个“名字”4.1 聚类中心不是用来盯着看的是用来读差异的模型跑完后你拿到的是每个簇的中心点坐标。这个中心点可以理解成这个群体的“平均脸”——把维度标准化后对比某个簇的中心和全体样本的均值明显偏高或偏低的特征就是这个群最鲜明的行为标签。我拿一个真实跑过的典型结果举例。假设全体用户的画像大致是平均 45 天没买东西每月买 2.3 次月度消费 380 元折扣敏感度 0.35。跑出 5 个簇后的中心表大概长这样簇编号Recency(天)Frequency(次/月)Monetary(元/月)折扣敏感度可能的用户类型簇086.512500.12高价值忠诚客簇1204.26200.28潜力成长客簇2351.82100.62价格敏感型簇3900.83300.40沉睡唤醒客簇41501.14800.18流失风险客看着这张表其实不用写报告你也能给每个簇起名字了。簇0最近 8 天内买过东西、一个月买 6.5 次、月度花 1250 元、对折扣几乎不敏感这明显是平台的核心用户不用券也买属于“高价值忠诚客”。簇2虽然也在活跃但折扣敏感度极高说明他们是跟着优惠走的补贴停了可能就流失属于“价格敏感型”。簇3最近 90 天没买过东西历史金额中等属于沉睡但还有价值的人群。簇4的 Recency 高达 150 天但历史消费金额比簇2还高说明曾经消费能力不错现在已经流失且比簇3流失得更久更需要区别对待。给簇命名的原则有两个一是业务可理解名字要能让运营同事一看就懂二是行为特征鲜明尽量不要命名为“普通用户”这种什么都装进去的名字。我一般会在命名前把簇中心表发给业务方一起看因为他们在第一线有时候会给出你想不到但是很有洞察的名字比如“促销羊毛党”“深夜剁手族”这种名字一旦起好沟通效率立刻翻倍。4.2 用可视化把分群“画”给业务方看拿到分群结果后给业务方汇报时最好的辅助工具不是簇中心表格而是一张能“看懂”的图。我最常用的有两种。第一种是雷达图。把每个簇在标准化后的几个核心特征上画成多边形一个簇一条线重叠在一起看特征轮廓。适合展示的特征数量别超过 8 个否则雷达图会密密麻麻看不清。比如特征选 Recency、Frequency、Monetary、折扣敏感度、类目覆盖数、平均客单价这六维每个簇就是一个六边形哪个簇在哪条轴往外突一眼就能看出差异化。这里我提一句雷达图需要把 Recency 这类“越小越好”的特征做反转处理比如取其倒数或者取负值否则“最近购买”会画成内缩看图的人会误读。第二种是 PCA 降维散点图。把标准化后的高维特征用 PCA 压到二维然后用不同颜色标记不同簇看是否形成肉眼可辨的群体团块。这一段强烈建议在报告里放图因为非技术的人对“聚类质量”没有概念但对图上颜色分明的几坨点非常买账。但你要心里清楚PCA 降维后的二维分布只是可视化的近似不代表每个样本在两维上的真实距离关系有些在高维空间里分得很开的簇投影到二维后可能重叠这很正常别因此怀疑模型。from sklearn.decomposition import PCA import matplotlib.pyplot as plt import seaborn as sns pca PCA(n_components2) X_pca pca.fit_transform(X_scaled) plot_df pd.DataFrame({ pca1: X_pca[:, 0], pca2: X_pca[:, 1], cluster: rfm[cluster] }) plt.figure(figsize(10, 6)) sns.scatterplot(dataplot_df, xpca1, ypca2, huecluster, alpha0.6)还有一个重点提示PCA 的散点图看着分得越开越容易让业务方对分群质量有过度信心。你可以在汇报时加一句“这是为了可视化模型本身是在高维空间里聚类的”防止对方误以为你们的聚类就是在这张二维图上做的。4.3 用户画像落地从簇标签到运营动作分群给完名字之后最关键的转化动作就是把每个群的用户故事讲清楚然后给出对应的运营策略。这一步做得好模型的价值才能真正体现出来。我总结一下电商场景里比较常见的分群运营策略可以套用到大多数项目用户群核心特征运营动作高价值忠诚客频次高、金额高、折扣不敏感VIP专属客服、积分加速、新品优先体验、生日礼盒潜力成长客频次和金额中等、活跃度上升交叉销售推荐、满赠升级活动、会员等级冲刺价格敏感型折扣敏感度高、复购不稳定大促定向券、凑单满减、清仓特卖优先推送沉睡唤醒客最近很久没买、历史价值尚可有吸引力的专属唤醒券、渠道偏好触达、老用户回归礼流失风险客已流失很久、历史金额高高价值流失预警、人工客服回访、竞品对比挽留运营策略不是分完就结束你要输出一个真正能让系统用起来的交付物用户 ID 和群标签的映射表。这张表接入运营后台后运营人员就能按群标签圈选人群推不同的文案、不同的优惠券、不同的活动页面。这是聚类从“分析报告”变成“生产工具”的关键一步。我每次都会把映射表导成 CSV 或直接写回数据库同时给运营一份一页纸的画像说明写清楚每个群的特征均值、典型用户示例、建议动作版而不是丢给他们一个几十页的 PPT。落地之后还要设置效果评估。怎么判断这次细分对业务真正有效我一般选三个核心指标做前后对比各群的次月复购率、人均购买次数、客单价。每个群单独看比如高价值忠诚客的客单价有没有因为 VIP 策略上升沉睡用户的唤醒率有没有明显改善。有条件就套 AB 测试框架没条件至少做时间序列上的前后对比用数据说话而不是用感觉说话。5. 常见问题与排查技巧实录5.1 K-Means在用户细分中高频踩坑做用户细分的项目多了我踩过的坑和身边团队踩过的坑都差不多。汇总成一个速查表省得你从头趟一遍。症状可能原因解决思路同样代码每次跑出的标签顺序不一样聚类初始化随机性n_init 太小固定 random_staten_init 调到 10 以上某个簇只有一两个样本异常值干扰或 K 值过大先做分位数截尾处理异常值试着减小 K标准化后某些特征仍主导结果特征本身偏态严重先做 log 变换再标准化分群结果业务上解释不通特征选得不对或 K 不合适回炉特征工程跟业务方重新对齐目标PCA 散点图上簇完全重叠高维空间中可能本来就是渐变的无明确边界不强求视觉分离回到指标和业务判断聚类结果“每次都不稳”数据量小或特征方差分布不均匀用固定种子复现必要时对全量用户采样后再聚类还有两个高频问题想单独展开。一个是“空簇”问题理论上 K-Means 训练后每个簇都至少有一个样本但如果你的数据里有极端孤立点可能出现某个簇中心附近几乎没人甚至中心在迭代过程中被孤立点拉走。解决办法还是那句话先把异常值处理干净再考虑调 K。另一个是大数据量场景如果用户量达到百万级甚至千万级直接对所有样本跑 K-Means 会非常慢我建议先采样一部分代表性用户训练聚类模型然后用训练好的模型对全量用户做 predict 打标签或者改用 MiniBatchKMeans 这类流式训练的变体。5.2 让聚类结果真正被业务用起来很多团队的聚类项目做完了模型文件躺在 notebook 里分群表放在共享盘里过两个月数据更新了谁也没想起来重新跑。这种“一次性聚类”的交付方式价值会随时间快速衰减。我的习惯是把聚类做成一棵可持续运行的“树”。首先模型文件要保存下来用 joblib 或 pickle 存好这样新增用户可以随时调用 predict 分群。其次分群映射表定期更新比如每月初用最近 90 天的数据重新跑一次聚类对比这次和上次每个群的人数占比、特征均值。如果某个月发现“高价值忠诚客”的占比突然从 8% 掉到 5%或者大量用户从“潜力成长客”漂移到“价格敏感型”这就给业务方拉响了一个预警信号说明大盘消费行为在变化。这里我分享一个亲身经历某项目在双十一大促期间因为全平台用户购买金额整体抬高聚类结果里“价格敏感型”人群占比暴增旧模型拿新数据一 predict大量中高价值用户被判成了价格敏感。后来我在流程里加了“分群稳定度监控”即两次聚类结果之间每个簇的用户重叠率统计重叠率低于某个阈值就触发模型重训。这个指标很快就帮团队定位了问题建议你也加上。另外聚类模型的 predict 和训练时的标准化工序要打包成一条流水线。因为 predict 新用户之前必须用训练时的 scaler 对新数据做同样的标准化否则特征空间对不上。我就见过有人拿新用户原始数据直接塞进旧模型得到的分群结果乱七八糟最后查了半天发现漏了标准化这一环。这条经验对任何用 sklearn 做聚类建模的团队都适用。5.3 什么时候需要换算法虽然这篇是 K-Means 实战但我也要诚实地说一句K-Means 不是万能的它最适合的场景是“簇近似球形、大小相对均衡、没有明显噪声”的连续数值特征。真实用户行为数据常常不满足这个假设。比如某个平台里有一群“退换货特别多的用户”和“正常购买用户”它们之间的边界可能是非球形的K-Means 就很容易把这些人切得七零八落。换算法的时机一般这样判断如果经过特征工程和调参分群结果依然在业务上支离破碎或者轮廓系数长期低得离谱就可以考虑其他方法。DBSCAN 适合带噪声的非球形簇能自动识别离群点代价是需要调邻域半径和最小样本数层次聚类适合希望看到“由粗到细”不同粒度分群的场景高斯混合模型GMM则能输出每个用户属于各群的概率适合用户可能同时属于多个群的情形。这个表格供你快速参考算法优点局限适合场景K-Means简单快速、大规模友好、结果易解释簇形状假设球形、对噪声敏感、需指定K市场细分第一版、大规模用户分群层次聚类输出树状图、不需预设K计算复杂度高、对噪声敏感小样本探索性分析DBSCAN自动识别噪声、支持任意簇形状密度不均时效果差、参数敏感有大量噪音点的场景GMM软聚类、输出概率、可表达椭圆簇模型更复杂、训练稍慢用户可能跨多个群的场景但我还是要强调一句算法本身不是项目成败的关键。根据我的观察超过一半的“聚类效果差”其实出在特征工程和数据预处理的环节而不是 K-Means 这个算法不适用。换算法之前先问自己三件事特征口径对不对标准化做了没有异常值处理了吗这三件事都没问题再考虑换成 GMM 或 DBSCAN 也不迟。最后再分享一个我在实际项目中反复用到的小技巧聚类结果出来后不要只在数据上看差异一定要做一次“人工体检”。每个簇随机挑出 3 到 5 个用户打开他们的真实订单记录和浏览记录从头到尾看一遍。你会发现统计特征很难捕捉到的规律比如某个簇的人几乎都在晚上下单某个簇的人总是先加购三天后才购买。这些真实行为模式往往比任何聚类图表都更能帮助你给用户群起名字、设计运营策略。这个习惯帮我在不止一次项目里避免了“统计上完美、业务上文不对题”的分群方案你也可以试一试。