K-Means实战:用户行为洞察与市场细分完整指南
发布时间:2026/10/20 3:57:11 锦皓数字建站

上一篇文章我们聊了 K-Means 从零手写的实现细节这一篇我打算换一个完全不同的视角不谈数学推导也不纠结收敛过程而是把它放到一个非常具体、也非常常见的业务场景里用户行为洞察与市场细分。说实话我见过不少团队做用户分层要么还在用新老客户累计消费金额这种粗粒度标签要么靠产品经理拍脑袋定出来的几类人。这两种做法都有一个共同的毛病分类规则来自人的主观经验而不是数据本身的结构。市场细分这件事本质上是在回答一个问题——能不能让数据自己告诉我们用户大概分成几拨、每一拨人有什么共同特征这篇文章作为 K-Means 深度探索系列的第八篇我会带着一套完整可复用的实战思路走一遍从行为特征怎么设计、数据预处理有哪些坑到 K 值怎么选、聚类结果如何翻译成运营动作。文章里的数据用某电商 App 的模拟匿名行为记录来演示案例是虚构的但流程和代码思路是真实项目里可以直接照搬的。无论你是做用户增长、数据产品还是刚接触聚类算法的同学都能从这套流程里拿到可落地的东西。1. 为什么行为细分比人口细分更适合 K-Means1.1 传统用户画像的局限标签是贴出来的不是长出来的很多人提到用户画像第一反应是性别、年龄、城市、收入这几件套。这些属性不是不能用但在做精细化运营的时候它们往往不够用。举个例子同样是 25 岁、一线城市、月收入差不多的两个女生一个可能每周在短视频 App 上下单三次生鲜另一个可能半年才买一次美妆。如果只按人口属性分组她俩会被分进同一个格子但她们的行为模式、消费动机、内容偏好可能天差地别。人口属性的本质是静态描述它描述的是用户是谁而行为数据描述的是用户做了什么。对于市场细分来说做了什么往往比是谁更直接指向下一步的运营动作。用户行为是一连串事件序列访问、点击、加购、下单、复购、退款、浏览时长、使用时段……这些东西组合在一起才真正构成一个人在你产品里的行为指纹。传统的做法是业务方凭经验定规则比如高价值用户 近 90 天消费 5000 元然后把这个规则固化成标签。问题在于规则是线性的、单维度的而真实用户是多重特征的组合体。一个消费金额很高但只买过一次的用户和一个消费金额稍低但每周都回购的用户价值逻辑完全不同。规则标签很难自动发现这种交叉结构除非你把几十条规则全部人工枚举出来那工作量就失控了。1.2 K-Means 的聚类逻辑与市场细分天然同构K-Means 做的事情本质上就是让相近的人站在一起在特征空间里把距离相近的样本归到同一个簇让不同簇之间的差异尽量大。这个逻辑和市场细分的经典定义高度一致——市场细分就是要找到组内同质、组间异质的用户群体。具体到机制上K-Means 有三个特点让它特别适合行为数据第一它是无监督的不需要预先标注任何用户类别。你把特征矩阵丢进去它自己找结构。这正好解决了我开头说的靠主观拍脑袋的问题尤其适合那些你还没想清楚到底有哪几类人的探索阶段。第二它对连续型特征非常友好。行为数据里大量字段天生就是连续值访问次数、浏览时长、消费金额、下单间隔。K-Means 基于距离计算数值越接近行为越像非常自然。第三它的结果可以做反向归因。训练完之后你能拿到每个簇的聚类中心质心质心在不同特征维度上的值就代表这个簇的平均行为画像。这个画像可以直接读出来比如这个簇的 30 日访问次数是 3 次客单价是 80 元业务团队拿到这种数字很容易形成具体认知。1.3 用一个生活化类比理解它为什么奏效你可以把 K-Means 想象成图书馆闭馆前管理员整理自习座位的过程。管理员并不知道今晚来的人会分成几拨他只是观察每个座位上的人做了什么有人在刷题、有人在用电脑写代码、有人在看书做笔记。他根据这些行为习惯把桌子重新归置成几个区域——纯刷题区、电脑办公区、安静阅读区。整理完之后新来的同学会自然走向适合自己的区域管理员也能为每个区域配置不同灯光和桌椅。这个过程和 K-Means 几乎没有区别没有事先规定世界上只存在三种自习者而是让行为相似的人自然聚拢再由你管理员去观察每个区域里的人在做什么给区域起名字。市场细分就是这个思路先让算法告诉你数据里存在几类行为模式再由你用人话给每类用户下定义。2. 带你看完整实战流程从原始行为日志到用户分段结果2.1 先定义分析单位与时间窗口这是最容易忽略的第一步任何聚类实战的第一步都不是写代码而是明确两个问题聚类对象是谁用哪一段时间的什么行为来刻画他在用户市场细分这个场景里聚类对象通常是用户 ID也就是把一个用户在一段时间内的行为汇总成一行特征向量。而时间窗口的选择直接影响特征的含义。我习惯分场景处理如果产品处于快速成长期用户生命周期短行为变化快时间窗口取 30 天比较合适。窗口太长早期行为和近期行为混在一起刻画的是历史画像而不是当前状态窗口太短低频用户的特征会大量为零区分度不够。如果产品是低频高客单类型比如装修、买车、保险用户一年也就几个关键动作那窗口可以放宽到 90 天甚至一年同时要降低访问频次类特征的权重提高关键事件类特征的权重。我在模拟案例里取的是近 90 天窗口覆盖 10 万个匿名用户。为什么用 90 天因为我要同时刻画整体活跃度和促成购买的行为链路90 天足够让低频用户也露出一些行为轮廓又不会跨度太长导致季节性因素把人群切得过于随机。2.2 行为特征体系的搭建RFM 打底再加两层行为偏好特征工程是整个流程里投入产出比最高的环节。K-Means 本身不会替你想什么特征重要它只会忠实地按照你给的特征去划分距离。所以特征设计直接决定聚类结果的质量上限。我常用的套路是三层结构也就是 RFM 基础层、偏好层、节奏层RFM 基础层是用户价值分层的标配。RRecency是最近一次消费距今多少天FFrequency是窗口内消费次数MMonetary是窗口内累计消费金额。这三个字段在绝大多数电商、内容付费、教育产品里都好使因为它们直接对应活跃度、忠诚度、消费力三个最核心的商业维度。偏好层解决的是用户为什么来这里的问题。比如商品类目偏好美妆、数码、食品、家居各自消费占比内容场景偏好直播、短视频、图文详情页的停留时长占比渠道偏好是先从搜索进店还是从推荐位进店还是从公众号文章跳转进来。这些特征决定同一个高消费用户内部还能不能再切分。节奏层刻画的是用户以什么节奏使用产品平均访问间隔、一天内的活跃时段分布比如晚上 10 点到凌晨 2 点占比高、周末和工作日的活跃差异。节奏特征对做推送策略特别有用因为它决定了你应该在什么时间点触达这群人。我在模拟案例里最终选了 8 个特征进入聚类模型而不是把 30 多个字段全部丢进去。选特征的过程其实是一个反复去掉不相关维度的过程后面我会专门讲为什么无关特征是聚类的干扰项。2.3 数据清洗与标准化别让量纲毁了整个聚类特征设计完之后直接跑 K-Means 是新手最容易犯的错误。这里有两道必须过的关卡。第一道是缺失值与异常值。行为数据里最常见的缺失是某用户没有某类行为比如近 90 天没有下单那么消费频次就是 0这不算缺失保持 0 即可。真正要处理的是极端离群值比如一个 B 端批量采购账号90 天消费 200 万元这个值会把M 值所在的维度的尺度拉得很大。处理办法不是强行删掉而是做截尾处理winsorize把超过 99 分位的值统一缩放到 99 分位值。这样既保留了真实业务含义又不会让极端值把整个聚类的簇中心带偏。第二道是标准化。K-Means 是基于欧氏距离的算法它非常在意特征的单位。消费金额的单位是元访问次数的单位是次/天活跃时段的单位是占比这三者数值范围完全不在一个数量级。如果不做标准化累计消费金额这个维度会因为数值大而在距离计算中占据绝对主导地位其他特征全部形同虚设。我用的标准化方法是 z-score对每个特征减去均值、除以标准差让所有特征都在同一尺度上比较。实际项目里如果你更在意极端值的鲁棒性也可以用 RobustScaler它基于中位数和四分位距对离群值不敏感。半年前我做过一次对比实验在同样一组电商数据上用 z-score 和用 RobustScaler 得到的人群结构基本一致但 RobustScaler 在存在少量异常账号时更稳所以我现在的默认选择是它。2.4 选择 K 值的实操节奏统计指标和业务解释要同时看K 值就是最终把人分成几类。这一步没有标准答案我的经验是统计方法初筛 业务可解释性终判。统计方法先跑一轮。最常用的是肘部法则Elbow Method画簇内误差平方和SSE随 K 值变化的曲线找那个下降速率明显变缓的拐点。还有一个指标是轮廓系数Silhouette Score值越大说明簇内越紧凑、簇间越分离。我在案例数据上跑了 K2 到 K10结果很有意思轮廓系数在 K2 时最高但如果你真的只分两类对业务几乎没有指导意义——高价值用户和低价值用户这种分法不需要聚类也能做。SSE 曲线的拐点在 K4 左右再往上去曲线就变得平缓。这时候就轮到业务判断上场了。我分别看了 K4、K5、K6 三种结果的质心特征最后选择了 K4。原因不复杂第一四个簇的画像差异非常清晰每一个簇都能用一个业务短语概括第二每个簇的样本占比都在 10% 以上没有出现某个簇只有 3% 的人这种过于碎片化的情况第三评分和策略执行系统能承接的运营分组数量有限超过 5 个组日常运营根本来不及针对每一组都设计差异化动作。这里我想强调一个很多教程不会提的点K 值选择不是单纯的数学问题它要同时考虑业务资源的承载能力。你分了 8 个簇每个簇都看起来很有特色但运营团队只有 3 个人做不了 8 套不同的运营方案。在可解释性和可执行性之间找到平衡才是真正的实战。2.5 聚类训练与画像输出一套可以直接跑通的 Python 示例把前面的准备落到代码上整个流程其实很紧凑。以下是一个可以在 Jupyter Notebook 里直接跑的最小示例import pandas as pd import numpy as np from sklearn.preprocessing import RobustScaler from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score # 读取特征宽表每行是一个用户列是行为特征 df pd.read_csv(user_behavior_features.csv) features [recency_days, frequency_cnt, monetary_amt, category_food_ratio, category_beauty_ratio, night_session_ratio, avg_visit_interval_days, coupon_sensitive_score] X df[features] # 1. 截尾处理抑制极端值 for col in features: upper X[col].quantile(0.99) X[col] X[col].clip(upperupper) # 2. 标准化RobustScaler 对离群值更稳健 scaler RobustScaler() X_scaled scaler.fit_transform(X) # 3. 用肘部法则快速初筛 K 值 sse [] k_range range(2, 11) for k in k_range: model KMeans(n_clustersk, n_init10, random_state42) model.fit(X_scaled) sse.append(model.inertia_) # 4. 选中业务可解释的 K 值训练最终模型 best_k 4 final_model KMeans(n_clustersbest_k, n_init10, random_state42) labels final_model.fit_predict(X_scaled) # 5. 把聚类标签写回原表并输出每个簇的质心画像 df[cluster] labels profile df.groupby(cluster)[features].mean() print(profile) # 6. 每个簇的样本占比 print(df[cluster].value_counts(normalizeTrue))这里的n_init10是防止 K-Means 因为初始中心点随机性而陷入局部最优random_state42保证结果可以复现这两行在实战里千万不要省。输出画像之后我一般会打印每个簇的平均特征值然后用一张表格来回反复对照给每个簇做判断。3. 聚类结果的价值不在分堆而在人群洞察3.1 把簇翻译成业务标签质心不是终点命名才是聚类跑完你得到的是一堆数字每个均值、每个占比。这些数字不会自动说话必须由你带着业务理解去解释它们把每个簇翻译成一句所有人都能听懂的话。在我的模拟案例里K4 的簇质心大致长这样数值做模糊处理簇编号最近消费天数消费频次累计金额夜间活跃占比特征速写簇0450.812018%长期沉默的边缘用户簇1125.286048%夜间冲动型高频买家簇262.142022%稳定刚需型日间用户簇329.6210035%高价值重度核心用户只看质心数据我给出的业务命名如下簇0沉睡用户。最近一次消费在 45 天前频次很低金额也低这类人可能已经流失或者即将流失。对他们核心策略是唤醒和召回而不是催下单。簇1夜间爆发型买家。消费频次不低客单不高金额中等但夜间活跃占比接近一半。这类人典型的行为模式是睡前刷到什么就买什么决策路径短对价格和内容种草敏感。策略重点可以放在晚间推送、直播秒杀、冲动型商品推荐上。簇2日常刚需型用户。访问和消费节奏稳定白天为主最近一次消费只有 6 天前。这类人的需求明确买东西大多是有目的性的。策略重点是提升客单和复购比如满减凑单、周期购。簇3核心价值用户。频次接近每周两次累计金额 2100 元活跃时段分布均衡基本把产品当作高频刚需工具。他们是整个平台最珍贵的资产策略重点是专属服务、会员权益、提前体验新品而不是用价格战去打扰他们。命名的过程看似简单但极其重要。因为只有当你把人说成夜间爆发型买家运营团队才知道该做什么如果你说簇1 的质心在第二和第五个特征维度上偏高没人会在意。3.2 用簇质心和业务指标对照表做策略推导命名只是第一步真正的洞察来自簇特征和业务策略之间的因果链。比如簇1 的夜间活跃占比是 48%这是个很有意思的信号。如果产品的推荐系统目前是按时间均匀分配的那说明这个簇的用户在过去 90 天里深夜打开 App 后拿到的推荐内容并没有被专门优化过。也就是说聚类结果暴露出了一个供给和需求不匹配的机会点。每次做完聚类我都习惯做一个策略推导矩阵格式大致是簇数据特征用户意图推断策略动作预估发力点沉睡用户访问间隔拉长无购买被竞品分走 or 需求消失短信优惠券召回唤醒效率夜间爆发型夜间活跃高客单低情绪型种草消费晚间场直播、限时秒杀转化率、客单价刚需用户白天访问稳定目标明确比价为主周期购、满减凑单复购率核心用户高频高额全时段高度依赖产品会员权益、专属客服留存和 LTV这个矩阵的价值在于它把聚类结果从描述性分析升级成了指导性分析。看到夜间活跃高你要追一句那夜晚这个场景我们有没有专门的内容场和货品场如果没有这就是业务动作。3.3 细分的下一步验证、迭代与动态更新聚类结果出来之后千万不要直接发给运营同事就完事。一个负责任的建模流程至少要再做三件事第一件事是验证簇的稳定性。把样本随机分成两份分别聚类看两个结果中每个簇的占比和质心是否接近。如果换一批样本簇的结构就变了说明 K 值可能选大了或者特征里噪声太多。稳定性验证花不了多少时间但能帮你在给别人讲结果时心里有底。第二件事是追踪簇的时间演化。这个月的簇画像和上个月的簇画像对比观察这个簇的人变多了还是变少了特征向哪个方向漂移。比如核心用户占大盘比例从 12% 掉到 9%这是一个非常值得警惕的信号值得拉出明细看看到底发生了什么。第三件事是建立动态更新机制。用户的聚类标签不应该是永久的。我见过有人跑完一次聚类就把标签写进数仓当月月报里用半年结果后面的活动效果一次比一次差。聚类分析一定要设定更新周期一般按月更新如果业务变化快按周更新更好。因为用户行为是流动的上个月他是沉睡用户这个月可能已经被一场大促激活再用沉睡策略去触达他反而会造成反感。4. 市场细分实战中的五类坑我替你踩过了4.1 不做标准化量纲大的特征绑架聚类结果这是我在早期项目里犯过的错也是最容易自查的一个坑。有一回我把消费金额、访问天数、注册时长三个特征直接丢进 K-Means聚类出来的结果几乎等同于按消费金额从低到高切成三段其他特征完全不起作用。原因很简单金额的方差远大于另外两个特征在欧氏距离计算里金额维度的差异主导了几乎所有样本之间的距离。怎么判断自己的结果是不是被绑架了一个简单方法是看每个簇的质心在不同特征上的区分度。如果只有金额这一个特征呈现明显的梯度其他特征在各簇间几乎没差别那基本可以断定标准化环节出了问题。解决方式前面说过z-score 或者 RobustScaler先标准化再训练。4.2 只看肘部图选 K 值统计指标不是全部业务解释才是肘部图是一个很好的初筛工具但它给出的拐点经常带有主观性——不同人画出的肘部图可能对拐在哪里有不同判断。更麻烦的是在某些数据分布下SSE 曲线可能根本没有明显的肘部而是平滑下降这时候固执地找拐点会让你卡在原地。轮廓系数也是同理它在 K2 的时候往往最高但分两类对绝大多数业务场景没有意义。我的建议是把统计指标当成候选集生成器而不是决策机。先用肘部法和轮廓系数圈定一个 K 的范围比如 3 到 6然后逐一检查每个 K 值下的簇画像把那些有两个簇长得几乎一样或者某个簇质心是另一个簇的子集的结果淘汰掉剩下的才可能是真正适合你业务的那个数。4.3 把所有特征一股脑丢进去无关维度的噪声会稀释聚类结构特征越多聚类结果不一定越好。这是 K-Means 一个反直觉的特性在高维空间里距离变得均匀所有点之间的距离都差不多簇结构反而会被稀释。我在一个内容社区项目里吃过这个亏当时把 20 多个行为特征全部丢进模型结果每一类人群的轮廓都很模糊质心之间差异极小。后来做了一次特征筛选只留下 6 个和内容消费深度高度相关的字段聚类结果立刻清晰了。筛选的方式很简单先看特征两两之间的相关性强相关的特征只保留一个再看每个特征的方差方差接近 0 的特征基本没有区分力直接删掉最后回到业务问自己这个特征如果取不同值运营动作会不一样吗不会就不放。4.4 把聚类结果当永久标签静态分群会错过用户的变化每次做完聚类我都会提醒自己一件事这张用户分类表只是一个快照。市场细分的价值在于动态捕捉用户行为结构的变化而不在于建立一劳永逸的档案。举个例子前面案例里的簇0沉睡用户在两个月后可能有一部分人因为一次大促重新活跃并转化成了簇2刚需用户。如果你继续用老标签给这部分人推送唤醒优惠券他们大概率不会买账因为你给了一个已经在活跃状态的人沉睡用户才应该收到的优惠。这就是静态标签带来的资源错配。解决方法是给标签加上时间戳并建立一个简单的状态迁移监测。每次聚类之后统计每个老簇的人分别流向了哪些新簇就能得到一张用户状态迁移矩阵。如果从沉睡到核心的迁移比例异常升高往往说明某个运营动作或者产品策略非常有效值得复盘放大。4.5 把相关性误当因果聚类是分组工具不是归因工具最后一个坑同时也是最容易在汇报时翻车的坑聚类结果反映的是特征之间的共现关系不是因果关系。比如簇1 显示夜间活跃占比高和消费频次高同时出现这不等于引导用户在夜间活跃就能提高消费频次只是这两件事在这个人群里伴随出现。有可能它们背后真正的原因是一个共同因素比如这批用户拿的是夜班族他们的生活节奏整体后移白天本来就在上班不管推不推送他们都在晚上购物。在实际落地策略的时候要带着假设检验的视角先基于聚类结果提出业务假设夜里推送对夜间人群有效再通过 A/B 测试或者增量分析去验证而不是直接把聚类结果当成既定的因果规律去执行。做分析的时间久了你会明白聚类给你的是线索不是结论真正有价值的是后续那些验证动作以及验证完成后回过头来对人群定义的修正。最后聊几点这套流程中的个人体会跑过几轮用户分群之后我最强烈的体感是特征工程花的时间永远值得。调 K 值、换标准化方法最多只能让结果在边缘上变好一点但如果你把会话流、购买链路、时段偏好这些维度设计得足够贴近业务聚类结果会自己清晰到让人惊讶。还有一件事是聚类项目一定要和业务方一起解读结果不要让算法同学独自完成命名。同一个簇做增长的人看到的是可激活潜力做留存的人看到的是衰退预警做体验的人看到的是浏览路径缺陷。不同视角的碰撞才会让一个簇的定义越来越接近真实用户。K-Means 给了你一把刀怎么用它把用户洞察切出来仍然要靠对业务的理解。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。