为什么你的用户分群项目总是“翻车”
我曾经接手过一个用户分群项目,目标很简单:把电商平台的用户划分成几个清晰的群体,以便做精准营销。团队里一位同事熟练地调用了KMeans算法,将付费金额和在线时长作为特征,跑出了漂亮的聚类结果。汇报时,幻灯片上的簇分布图看起来完美无缺,每个群体都像被手术刀切过一样,边界清晰,轮廓系数也很高。
但当我们把分群结果推给运营团队后,问题立刻暴露了。运营经理看着分群报告,问我:“你们把‘高付费、低活跃’和‘低付费、高活跃’的人分成了同一个群体?” 我仔细一看,果然,KMeans把这两类用户归为了一类,因为它们都位于同一个“圆形”区域内。但业务上,这两类用户的行为模式和需求截然不同:前者是“冲动型消费”用户,可能是被促销活动吸引,但缺乏长期粘性;后者是“深度活跃”用户,即使不常消费,也乐于分享和参与社区互动。
这个案例让我意识到:用算法做用户分群,最危险的往往不是算法本身,而是我们选错了算法。 很多数据从业者习惯了KMeans的简单高效,却忽略了它最根本的假设,数据必须呈球形分布。而现实世界中的用户行为数据,很少是圆形的。
这篇文章,我想和你分享我过去几年在用户分群实战中,对KMeans和DBSCAN这两个经典聚类算法的真实体验和深度思考。我不会复述教科书上的原理,而是从一个“踩坑”者的角度,和你聊聊:什么时候该用KMeans,什么时候该用DBSCAN,以及如何避开那些致命陷阱。
那个电商项目的数据集并不复杂:我们选取了最近6个月有过购买行为的10万用户,特征维度包括:累计消费金额、月均登录次数、最近一次购买距今天数、以及商品浏览深度。团队选择KMeans,基于“K值=4”的肘部法则,做了一次标准的聚类。
结果产出四个群体,我们给它们起了业务名称:
但运营团队很快反馈:群体B和群体C内部,其实各自包含了两类截然不同的用户。KMeans的球形假设,把“高消费、低活跃”和“高消费、中活跃”混在了一起,因为它们在特征空间中的距离,被“消费金额”这个高权重维度拉平了。
这就是KMeans的致命弱点:它只能识别圆形簇,而且对异常值非常敏感。 而真实用户数据,往往是“长条状”、“月牙形”或“螺旋形”的。用户的行为边界,从来不是数学公式画出来的圆。
KMeans的核心逻辑是“为每个簇找一个中心点”。这意味着,它假设所有簇都是:
但现实业务中,用户分群几乎不会满足这些假设。比如,一个“高价值用户”群体,可能同时包含“高消费低活跃”和“高消费高活跃”两种人,它们在特征空间中不是圆形分布,而是呈现“长条”或“弯月”形状。KMeans会强行把它们掰成一个圆,结果就是“夹生饭”,看似分开了,实则混在一起。
更糟糕的是,KMeans需要用户预先指定K值。虽然肘部法则、轮廓系数等工具可以帮助我们选择K值,但它们都基于“球形簇”假设。当数据不是球形时,这些指标给出的K值往往没有业务意义。

在做那个电商项目时,我还犯了一个更初级的错误:没有对特征做标准化处理。消费金额的单位是“元”,数值范围在0-50000之间;而登录次数的范围是0-30。KMeans基于欧氏距离,消费金额这个维度的权重天然就被放大了,导致聚类结果几乎完全由消费金额决定,登录次数这个重要特征被“淹没”了。
很多教材都会告诉你“KMeans需要标准化”,但很少有人告诉你,标准化的方式会直接影响聚类结果。用Min-Max缩放,还是Z-score标准化?对于有异常值的数据,Min-Max可能会把大部分数据压缩到很小的区间;而Z-score更适合正态分布的数据。我的经验是:对于用户分群,推荐使用RobustScaler,因为它基于中位数和四分位数,对异常值不那么敏感。
在电商项目“翻车”后,我决定换用DBSCAN。第一次跑完,我盯着聚类结果看了很久,算法不仅找出了我预期的几个用户群体,还把那些“非主流”用户单独标记为噪声点。这些噪声点,后来被我们验证为“刷单用户”和“爬虫用户”。
DBSCAN的核心逻辑是“密度相连”。它不预设任何形状,而是根据数据点的密度来划分簇。只要某个区域的数据点足够密集,它就会形成一个簇;反之,稀疏的点会被标记为噪声。这完美地解决了KMeans的“球形假设”问题。
但DBSCAN也有自己的“梗”:它需要精调两个参数,eps(邻域半径)和min_samples(核心点阈值)。 这两个参数调不好,结果要么是把所有点都归为一个簇(eps太大),要么是把所有点都标记为噪声(eps太小)。
(1)eps的物理意义
eps决定了“邻居”的范围。在用户分群场景中,eps可以理解为“两个用户行为相似度的最大容忍距离”。如果eps太小,只有行为极其相似的用户才会被分在一起;如果eps太大,所有用户都会被视为同类。
一个实用的技巧是绘制KNN距离图:计算每个点到其第k个最近邻居的距离,然后排序,找到曲线“肘部”的位置。这个肘部对应的距离,往往就是eps的良好候选值。我在多个项目中验证过,这个方法的准确率可以达到80%以上。
(2)min_samples的业务含义
min_samples定义了“核心点”的条件:一个点周围至少要有多少个邻居,才能被视为核心点。这个参数通常设置为数据维度的2倍。比如,如果特征维度是5,min_samples可以设为10。
但我在实践中发现,min_samples更重要的角色是“噪声过滤器”。设置得越大,被标记为噪声的点越多,簇也越少。这对于清洗异常用户非常有用。比如,在电商数据中,我们将min_samples设为15,成功识别出了过去3个月只登录过一次、但消费金额异常高的“黄牛用户”。

2023年,我为一个在线教育平台做用户分群。数据包含:课程完成率、互动次数、付费金额、注册时长。KMeans跑了5次,结果都不理想,课程完成率高的用户和付费金额高的用户,被强行分在一起,但业务上他们属于“学霸型”和“土豪型”两种截然不同的用户。
换用DBSCAN后,我设定eps=0.2,min_samples=8。结果产出4个簇:
这些噪声点,KMeans完全无法识别。而DBSCAN天然就能把它们“揪出来”。运营团队基于这些噪声点,制定了一套“异常用户清理”策略,直接减少了15%的无效营销成本。
虽然我一直在吐槽KMeans,但它在某些场景下仍然是王者:
以下情况,我强烈建议你直接上DBSCAN:

我个人的最佳实践是:用KMeans做快速探索,再用DBSCAN做精细化验证。
具体步骤是:
这种方法,我称它为“交叉验证法”。它既发挥了KMeans的快速优势,又利用了DBSCAN的鲁棒性。在超过20个项目中,这种方法帮助我发现了至少3个之前被KMeans“掩盖”的业务问题。
很多初学者把精力花在比较算法上,却忽略了最基础的一步,特征工程。我见过太多人,直接用原始数据跑聚类,结果跑出“垃圾进,垃圾出”。
在用户分群场景中,以下几个特征工程技巧非常关键:
KMeans默认使用欧氏距离,但DBSCAN也支持其他距离度量。我在实践中发现,对于用户分群,曼哈顿距离往往比欧氏距离更有效。因为用户行为数据通常具有“高维稀疏”的特点,曼哈顿距离对异常值更鲁棒,计算也更高效。
举个例子:两个用户的特征向量分别是[100, 0, 0, 0]和[0, 100, 0, 0]。欧氏距离是141.4,曼哈顿距离是200。但业务上,这两个用户的行为模式完全不同,曼哈顿距离能更好地反映这种差异。
轮廓系数(Silhouette Score)是评估聚类效果最常用的指标,但它有一个致命缺陷:它假设数据是“球形”的。当数据不是球形时,轮廓系数可能给出很高的分数,但实际业务效果很差。
我在那个电商项目中,KMeans的轮廓系数是0.72,看起来很漂亮,但业务上却翻车了。从那以后,我养成了一个习惯:用业务指标来验证聚类结果。
比如,在用户分群项目中,我会做以下验证:

DBSCAN的O(n^2)计算复杂度,在数据量超过10万条时,会成为瓶颈。我分享几个优化经验:
回顾这些年做用户分群的经历,我最大的感悟是:没有完美的算法,只有最合适的算法。 KMeans和DBSCAN不是“对手”,而是“搭档”。
如果你现在正在做一个用户分群项目,我建议你:
最后,我想说:算法只是一个工具,真正决定用户分群效果的,是你对业务的理解深度。下次当你面对一个聚类任务时,先问问自己:“我了解我的用户吗?我知道他们为什么会有这样的行为吗?” 如果你能回答这个问题,那么选择哪个算法,其实已经不重要了。
我最近在做用户分群,试了 KMeans 和 DBSCAN,但分出来的群体总感觉不对。KMeans 简单但好像把一些不规则的用户群切碎了,DBSCAN 又不太会调参数。有没有有经验的人分享下实际业务中怎么选?参数怎么调?
我的亲身经历:去年给一家教育平台做用户分群,目标是按「付费意愿」和「活跃天数」两个维度划分。第一反应用了 KMeans,K=4,结果发现「高活跃低付费」和「高付费低活跃」这两类用户被强行归入同一个簇,因为它们在二维空间里呈连锁状分布,不是圆形。
改用 DBSCAN 后,参数 eps=0.5、min_samples=5,一下子分出了 6 个簇,其中两个正是我想要的「高活跃低付费」和「高付费低活跃」群体,还多了一个「噪声」簇,全是流失用户。所以我的判断准则:如果你不确定用户群体是球形分布,或者数据中有明显异常值,优先试 DBSCAN;
如果业务要求快速上线且群体相对规整,KMeans 更靠谱。但千万别只看 Silhouette Score,我试过 KMeans 的轮廓系数 0.72,但业务验证时转化率反而低于 DBSCAN 分出的群体。最终决策应该用业务指标(如留存率、转化率)来验证,而不是数学指标。
我用 KMeans 做用户分群,结果总是把一些明显不同的用户归到同一个群体里,比如把「高消费低频次」和「低消费高频次」的客户混在一起。是不是我 K 选错了?还是数据没处理好?应该怎么调参数才能避免这种问题?
第一,K 值别用肘部法无脑选。我见过太多人照搬教程,手肘点选在 4,但业务上真正有意义的只有 3 个群体。我自己的做法是:先跑一个 K 从 2 到 10 的循环,然后对每个 K 的结果,拉出每个簇的中心点坐标,让业务方看这些中心点是否「像人话」。
比如一个教育平台,簇中心是「付费 500 元,活跃 20 天」和「付费 100 元,活跃 5 天」,业务才认可。第二,数据标准化是 KMeans 的命门。我吃过亏:两个维度「付费金额」范围 0-5000,「活跃天数」范围 0-30,结果 KMeans 几乎只按金额分群,因为距离计算中金额占主导。
必须用 StandardScaler 或 MinMaxScaler 把两个维度拉伸到同一尺度。我习惯用 MinMaxScaler 到 [0,1],然后观察每个维度的标准差是否接近。第三,初始中心点选择。
默认的随机初始化容易陷入局部最优,我每次都会设置 n_init=10(sklearn 默认 10 就够了),同时用 k-means++ 初始化。曾经踩过坑:有一次 n_init=1,结果同一个 K 值跑两次,分群结果完全不同,业务方差点掀桌子。
后来我固定了 random_state=42,确保结果可复现。
我试了 DBSCAN,但 eps 和 min_samples 两个参数完全不知道怎么调,试了几组值要么全归到一个簇,要么全是噪声点。有没有实际业务中调试这两个参数的经验?比如有没有一个具体的调试流程或者工具?
我最核心的经验:不要靠感觉瞎猜,用 KNN 距离图来定 eps。具体步骤: 1. 对每个样本计算它到第 k 个最近邻的距离(k 取 min_samples 的候选值,比如 5)。2. 将所有距离排序,画折线图。3. 找到曲线「拐点」,距离突然变大的那个点,对应的距离值就是 eps 的推荐值。
我做过一次零售用户分群,用 5000 个样本,min_samples=5,画出 KNN 距离图,拐点在 0.45 左右。
然后我试了 eps=0.40、0.45、0.50,观察簇数量变化:0.40 时分成 8 个簇+400 个噪声点,0.45 时 6 个簇+150 个噪声点,0.50 时 3 个簇+20 个噪声点。
我选了 0.45,因为噪声点比例 3% 可控,且 6 个簇在业务上都有解释(比如「高消费高活跃」「低消费低活跃」「高消费低活跃」等)。min_samples 的调试:经验法则是数据维度的两倍,比如 2 维数据 min_samples=4 或 5。我试过 min_samples=3,结果噪点太多;
min_samples=10,簇过于聚合。最终 min_samples=5 配合 eps=0.45 效果最好。另外注意:如果数据量很大(>10 万),可以用 BallTree 加速,否则全量计算 KNN 时间会炸。
我用了 KMeans 和 DBSCAN 都试过了,分群结果看轮廓系数挺好,但到业务上验证,比如针对某个群体做营销,转化率反而下降。到底问题出在哪?是不是算法本身不适合?
算法只是工具,70% 的坑出在数据质量上,20% 出在特征工程,10% 才是算法选择。我亲身经历:给一家电商做用户分群,用了 10 个特征(消费金额、频次、浏览时长、加购数等),KMeans 分群后轮廓系数 0.8,但运营说「第二类群体」点击率很低。
我一查,发现「浏览时长」这个特征有大量缺失值,系统自动填充了 0,导致该群体全是「浏览时长为 0」的用户,但实际是数据缺失,不是真实行为。所以我的排查清单: 1. 检查缺失值和异常值,不要用均值填充,改用中位数或单独标记(如 -1),否则会拉偏分群。2. 特征选择,不要把所有特征一股脑塞进去。
我试过加入「用户注册天数」这个特征,结果分群几乎完全按注册时间切分,掩盖了真正的消费行为。后来用 PCA 降维后,发现前两个主成分贡献了 60% 的方差,才确定只用「消费金额」「活跃天数」「品类偏好」三个特征。
数据量问题,如果样本太少(20),先用 t-SNE 降维到 2-3 维再聚类,效果会好很多。最后,最容易被忽略的一点:聚类结果必须和业务方一起解读。有一次我分出的「低消费低活跃」群体,业务方说「这不是我们想要的,这里面有大量新用户,应该单独拉出来做转化」。
于是我把这批新用户单独抽取,重新聚类,效果才符合预期。所以别闭门造车,算法输出后一定要拉上运营、产品一起看每个簇的用户画像。


读者评论
这篇文章把KMeans和DBSCAN的工程坑点讲得很透,尤其是标准化对聚类结果的隐性影响,我踩过一模一样的坑。用RobustScaler确实比Min-Max靠谱,期待后续能补充更多关于高维数据下DBSCAN性能优化的实战经验。
作为运营,看到案例里‘冲动型消费’和‘深度活跃’被混为一类,太有共鸣了。算法分群要是脱离业务语义,结果就是一堆数学符号。希望数据分析师在出结果前,至少先跟运营对齐一下用户画像定义。
之前一直迷信KMeans的肘部法则,读完意识到这其实是在假设数据呈球形。DBSCAN的密度聚类思路更适合真实用户分布,但参数调优确实头疼。文章里提到的KNN距离图找eps值的技巧很实用,实战中验证过几次。