1. 为什么要用聚类做用户分析从拍脑袋分群到数据驱动先还原一个我真实遇到的场景。前阵子帮一家电商团队做用户运营支持运营同事找我提需求把我们用户分成高、中、低三类重点维护高的——我问怎么定义高她说按客单价大于500是高100到500是中小于100是低。这种分群方式我太熟了几乎所有电商运营一开始都是这个思路拿一个指标、切几个阈值、给用户贴标签。但实际跑完数据我就发现不对劲。按客单价切分出来的高价值用户里头混着两类人一类是确实有钱、复购频繁的优质客户另一类是几年才买一次、单次买很多但整体贡献很小的过路客户。如果一视同仁投喂高价值权益钱花了复购一点没起来。这就是单维度分群的根本问题——用户的消费习惯是多个维度共同决定的金额只是一个切面。聚类分析的价值正在于此。它不依赖你预先设阈值而是根据用户在所有特征维度上的距离自动分组让相似的聚在一起、不同的自然分开。这个项目用的就是最经典的RFM特征体系——最近购买时间(Recency)、购买频率(Frequency)、消费金额(Monetary)加上几个行为特征用Python的sklearn跑K-means聚类把几千个用户分成了五个行为差异明显的群体。每个群体的特征画像、运营策略都是事后从数据里长出来的而不是事前拍脑袋定义的。这个项目的完整流程可以复制到任何有过往订单数据的电商场景清洗数据、构建特征、标准化、选算法、定K值、聚类、解读分群、落地运营策略。后面我会把每一步的关键决策、代码、踩过的坑全写出来。适合谁看手里有用户数据但不知道怎么分群的运营和数据分析师以及刚学完Python基础、想找个真实项目练手的同学。这个项目不需要分布式、不需要大数据平台一台笔记本、几千条订单就能跑出有价值的结果。2. 从原始订单表到特征矩阵清洗和特征工程是决定成败的环节很多人觉得聚类分析的核心是算法其实不然。这项目做下来我的体感是数据清洗和特征构造占整个工作量的七成算法只占三成。因为聚类算法本身没有鉴别能力你喂给它什么特征它就基于什么特征分组。特征造得烂再好的算法也白搭。2.1 电商订单数据的典型脏数据问题我当时拿到的原始数据是一张订单流水表字段包括用户ID、订单创建时间、实付金额、商品类目、订单状态。看起来挺规整但一跑描述性统计就暴露问题了有订单状态为已退款但金额为正的脏记录这种订单应该直接剔除否则会把退款用户算成高消费用户有单笔订单金额为0.01元的异常记录明显是测试订单或者薅羊毛产生的会污染M维度的分布有同一个用户ID出现多次但注册时间对不上的情况通常意味着老系统迁移时用户ID合并过分析前需要用最新的对齐逻辑去重还有极少数用户的购买时间跨度横跨好几年但总购买次数只有一两次这类用户如果纳入分析会把时间窗口的统计口径搞乱。清洗逻辑我建议写成一段可复现的代码不要手动在Excel里删。我自己的做法是先定规则剔除退款订单、剔除金额小于等于0的记录、剔除测试账号通常能从用户名或邮箱正则里识别出来再按用户ID订单号去重。每一步清洗都打印损失了多少行数据方便回溯。2.2 特征设计RFM三件套之外还能加什么特征工程是整个项目里最值得花时间琢磨的部分。我构建了7个特征分三类第一类是经典RFM特征。R是最近一次购买距统计截止日期的天数越小说明用户越活跃F是统计时间窗口内的购买次数M是统计时间窗口内的累计消费金额。这里有个细节时间窗口的选择很重要。我用的这家店铺复购周期大约是一个月所以我取了最近90天的数据做时间窗口——太短会把低频但忠诚的用户误伤成流失太长又会让多年回归用户和持续活跃用户混在一起。如果你接手的是新品期或大促后的数据窗口要相应缩短产品周期越长窗口越长。第二类是消费行为特征。我在RFM基础上加了平均每单金额和购买类目数。平均每单金额和累计金额看起来很像但信息完全不同累计金额高可能是买了很多单便宜货也可能是买了几单贵的平均每单金额则直接反映用户的消费档次。购买类目数反映用户的宽度——只买一个类目的用户往往是刚需型跨多个类目的用户更愿意尝试平台的新品类。第三类是折扣敏感度特征。用实付金额除以订单原价总额算出平均折扣率这个特征能特别清晰地把价格敏感型和品质型用户分开。折扣率接近1说明用户几乎不打折不买折扣率低的用户则相反。import pandas as pd import numpy as np # 假设 df_order 是清洗后的订单表字段user_id, order_time, pay_amount, original_amount, category cutoff_date df_order[order_time].max() df_user df_order.groupby(user_id).agg( recency(order_time, lambda x: (cutoff_date - x.max()).days), frequency(order_time, count), monetary(pay_amount, sum), avg_order_value(pay_amount, mean), category_cnt(category, nunique), discount_sensitivity(pay_amount, lambda x: (x / df_order.loc[x.index, original_amount]).mean()) ).reset_index()上面这段代码有个地方要注意discount_sensitivity里用了df_order.loc[x.index]取原始订单的原价金额这种写法在groupby的lambda里会访问外层DataFrame数据量小的时候没问题但如果你的数据有几十万行这个写法会很慢建议先算好每笔订单的折扣率再groupby求平均。2.3 标准化和异常值处理这一步不做聚类结果基本报废特征构造完下一步不是直接喂给K-means而是要做标准化。K-means的核心是欧氏距离它假设所有维度对距离的贡献是等权的。但你看我这些特征monetary量级到几千上万recency只有0到90frequency可能是个位数如果不标准化monetary一个维度会完全主导距离计算其他特征全成了摆设。我自己第一次跑的时候就没重视这一步直接拿原始特征聚类出来的群体几乎只按消费金额分成了有钱人和穷人RFM里的R和F完全失去了区分作用。后来用StandardScaler标准化后再跑分群质量肉眼可见地提升。标准化方法我用的是Z-score标准化也就是减去均值除以标准差让每个特征变成均值为0、方差为1的分布。sklearn的实现很简单from sklearn.preprocessing import StandardScaler feature_cols [recency, frequency, monetary, avg_order_value, category_cnt, discount_sensitivity] scaler StandardScaler() X_scaled scaler.fit_transform(df_user[feature_cols])做完标准化之后我还顺手做了一步异常值截尾。电商数据里总有极少数大鲸鱼用户消费金额是均值十倍以上这种极端值会让K-means的质心计算被拉偏好几个簇都会围着这个异常用户转。我的做法是把每个特征超过99分位数的值压到99分位数不是删除用户而是压缩极端值的影响。这一步之后再看分布聚类结果稳定多了。3. 聚类算法选型K-means、层次聚类、DBSCAN各自的适配场景特征矩阵搞定之后面临的问题是用哪种聚类算法项目开始时我对比了三种最常见的算法这里把我的思考过程写出来供你以后选型参考。3.1 三种算法的核心逻辑和适用边界K-means的原理很多人背过随机初始化K个质心迭代地把样本分到最近的质心再重新计算质心位置直到收敛。听起来简单但它有两个隐含假设很关键一是适合凸形的簇二是所有簇的密度和规模差别不大。电商用户分群恰恰比较满足这个假设——各个人群规模虽然有差异但不会像地质数据那样出现一个极密团和一个极度稀疏的团并存的情况。层次聚类和K-means最大的区别是不用提前指定K它通过不断合并最近的两个簇自底向上或不断分裂自顶向下来生成一棵树状结构你可以从树状图里目测该切几类。它的缺点是计算量比K-means大样本量上万之后速度明显下降而且它对离群点更敏感——一个离群点会不断把别的点吸过来形成一个大簇。我这次为了对比在5000多个样本上跑了一次凝聚层次聚类耗时是K-means的八倍左右而且结果和K-means高度相似性价比不高。DBSCAN则是基于密度的聚类它把密度足够高的区域连成簇剩下的点标记为噪声。这算法最大的优点是能自动识别离群点不需要预设K。但它有个让人头疼的参数调优问题邻域半径eps怎么选没有通用规则而且当数据维度比较多时密度的计算会受维度灾难影响eps很难找到一个合适的值。我的特征是7维试了几组eps出来的结果要么全是噪声点要么所有用户挤成一个簇很难调到理想状态。3.2 为什么我最终选了K-means三种算法跑下来我最终选定K-means作为主模型理由很实际第一业务上我们对分群数量有预期。运营同事需要2到6个人群来匹配不同的投放策略K-means正好可以通过指定K来控制输出粒度不需要像层次聚类那样在树状图上做主观切割。第二电商用户分群的特征空间相对规整没有极端的形状和密度差异K-means的凸簇假设在这个场景下是成立的。这一点我用轮廓系数验证过K-means和层次聚类的轮廓系数几乎一样说明K-means没有因为假设限制而损失质量。第三工程上K-means快、稳定、可复现sklearn的KMeans接口一行代码就能跑迭代次数可控。对业务团队来说他们需要的不是一个教研级的算法而是一个每周可以稳定重算一次、结果不飘的模型。如果你手里数据集的类群形状差异大、或者你不确定该分几类我建议先用层次聚类跑一版看树状图再用DBSCAN验证下离群点数量最后用K-means出正式结果。三种算法各跑一遍互相印证比自己盲选一个要稳得多。4. 确定K值和验证聚类效果技术指标只解决一半问题K-means定了之后最让人纠结的是选K。这部分我想重点讲讲因为太多人只盯着肘部法则的图却忽略了业务验证这一步。4.1 肘部法则和轮廓系数的具体操作我用了两种经典指标辅助选K。第一个是肘部法则横轴是K值纵轴是该K值下的簇内误差平方和SSE。K增大时SSE一定会下降但下降幅度会逐渐放缓拐点处对应的K就是性价比最高的分群数。from sklearn.cluster import KMeans sse [] for k in range(2, 11): kmeans KMeans(n_clustersk, random_state42, n_init10) kmeans.fit(X_scaled) sse.append(kmeans.inertia_) # 画出SSE曲线后找拐点第二个是轮廓系数它衡量的是每个样本和它自己簇的相似度与和最近簇的相似度的差值取值范围在-1到1之间越大说明簇内越紧凑、簇间越分离。from sklearn.metrics import silhouette_score silhouette_scores [] for k in range(2, 11): kmeans KMeans(n_clustersk, random_state42, n_init10) labels kmeans.fit_predict(X_scaled) silhouette_scores.append(silhouette_score(X_scaled, labels))我当时跑出来的结果很有意思SSE曲线在K4、K5处都有明显拐弯轮廓系数在K2时最高这很常见因为分成两类最容易让簇间距离变大但K2的轮廓系数高不代表业务上能用——只有活跃和不活跃两个群运营照样不知道怎么差异化对待。所以我还做了一步从K3到K6逐个看每个群的业务画像看哪个K值下的分群最可解释。4.2 用业务可解释性做最终判断这一步是我觉得这个项目最有价值的部分。K的选择不能只看数学指标还要看分出来的群体在业务上能不能说得通、能不能差异化运营。我逐个K值核查K3时群体差异太粗糙高价值用户和潜力用户被揉在了一起运营没法精准投放K6时有两群的画像高度相似频率和折扣率几乎一样分群没有实质增量K5时五个群的RFM均值呈现出清晰的阶梯状分化每个群的消费习惯都能讲出一个合理的故事——从沉默流失用户到高价值忠诚用户都在各自的簇里自洽地聚成了一群。最终我选了K5。这里要特别提醒一下不要为了追求轮廓系数高而选K2或K3也不要觉得K越大模型越精细。聚类是业务工具不是学术竞赛分群的可解释性和可用性永远排在数学指标前面。我见过太多分析师卡在选K这一步知道用肘部法则但对业务说不清楚为什么选5不选4那就是还没把聚类结果真正变成业务资产。5. 聚类结果解读与分群画像从簇编号到用户标签K值定了模型跑完拿到了每个用户的簇标签但这只是中间产物。接下来要做的是把簇0、簇1、簇2翻译成高价值忠诚用户、沉睡唤醒用户这些业务语言同时用可视化验证聚类效果。5.1 降维可视化7个特征怎么在二维平面上展示7维特征没法直接画图我用的降维方式是PCA主成分分析把7维压到前两个主成分上然后画散点图每个簇用不同颜色标出来。from sklearn.decomposition import PCA import matplotlib.pyplot as plt pca PCA(n_components2) X_pca pca.fit_transform(X_scaled) plt.figure(figsize(10, 8)) colors [#4C72B0, #DD8452, #55A868, #C44E52, #8172B3] for i in range(5): plt.scatter(X_pca[labels i, 0], X_pca[labels i, 1], ccolors[i], s10, labelfCluster {i}) plt.xlabel(PC1) plt.ylabel(PC2) plt.legend() plt.show()需要说明的是PCA降维本身会丢掉一部分信息我这两个主成分大概解释了62%的方差散点图能看到大致的簇分布形状但个别点靠得近不代表它们在原特征空间里真的近。所以散点图是验证和展示手段不是判断聚类质量的依据。真正的判断依据还是回到特征均值表。5.2 各分群特征画像与运营策略设计跑完聚类后我做了个分群特征均值表一眼就能看出五类用户的差异分群用户占比最近购买天数(R)购买次数(F)累计金额(M)平均每单金额折扣敏感度高价值忠诚群12%8天12次6800元560元0.78成长潜力群21%15天6次2400元380元0.84价格敏感活跃群28%20天5次1300元240元0.62沉睡唤醒群25%58天2次800元350元0.88流失风险群14%85天1次300元290元0.92这五个群的故事非常清楚。高价值忠诚群是平台的现金牛R很低、F和M很高单笔消费也不差折扣敏感度中等说明他们不完全靠低价驱动是品质型用户运营上要侧重专属服务、新品体验、会员权益叠加而不是一味发大额优惠券——发券反而可能降低他们的毛利空间。成长潜力群最值得投入资源。他们的F和M都高于平均水平但还没到顶配折扣敏感度相对不高说明他们对平台的信任度已经建立运营方向是交叉销售——他们只买过1.8个类目通过个性化推荐和组合优惠引导他们尝试更多品类的空间很大。价格敏感活跃群是典型的跟着优惠走的用户。F不低但M不高平均每单金额明显低于其他群折扣敏感度0.62说明他们非常吃优惠。对这群人不要用感情留人用低价爆款、限时秒杀、满减叠加这些硬手段更直接同时可以通过签到领积分这类机制慢慢培养习惯。沉睡唤醒群已经一个多月没来了但历史数据显示他们曾经有不错的消费力。对这个群的第一动作不是发券而是先做流失原因探查——是竞品拉走了还是上次购物体验不好在没搞清楚原因之前盲目发券只会进一步拉低折扣敏感度把用户养成不优惠不回来的习惯。流失风险群基本可以宣告抢救无效了。R已经85天F和M都垫底这群人的召回成本远高于可能带来的收益。运营策略是低成本维持——邮件或短信在会员日统一触达一下即可把资源让给前三个群。他们的价值不在当下而在于防止沉睡变成永久流失。这轮分群做完之后运营团队最大的感慨是以前只知道高价值用户要重点维护但具体怎么维护没有方向。现在每个群都有鲜明的行为标签、量化的触达理由和差异化的策略方向投放效率的提升非常直观。6. 项目踩坑记录与工程化建议这些教训能帮你少走弯路这个项目前后跑了两周踩过的坑不少。挑几个有代表性的写在下面基本涵盖了做这类用户聚类项目最容易翻车的点。6.1 踩过的四个坑第一个坑是特征没标准化就聚类。这个前面提过我第一版结果直接被消费金额一个维度主导R和F特征毫无存在感聚类变成了按金额排名分段。后来加了StandardScaler才解决。这个坑几乎所有人都踩过区别只是踩多久出来。第二个坑是异常值没有处理。当时我看到有一个用户的消费金额是30000多是均值的十倍还多。这个人直接让K-means的质心偏移导致好几个群的人数分配失衡最大的群占了60%的用户。用99分位数截尾之后群规模分配才变得合理。记住K-means对异常值极其敏感因为它基于均值计算质心。第三个坑是忽略了对数变换。monetary和avg_order_value这两个特征都是典型的右偏分布——大部分用户消费集中在低段少数高消费用户拖着一条长尾。直接做Z-score标准化只是把偏态分布平移了没有改变分布的形态数值越大方差越大距离计算中这个维度的权重仍然会被极值拉高。我在处理完99分位数之后又对这两个金额类特征做了log1p变换让分布更接近正态后再标准化轮廓系数进一步提升。这一步让我意识到标准化之前先解决分布的偏度问题比标准化本身更重要。第四个坑是只算聚类不过业务。我一开始拿到簇标签就直接进下一步没先看每个簇的特征均值。后来做特征均值表的时候才发现有个簇的平均购买次数和平均折扣率跟另一个簇几乎一样说明这个K值下有一个簇没有实际区分价值。从那以后我每次跑完聚类都强制自己先看群画像再谈下一步。6.2 从一次性探索到可复用的工程化流程项目从探索阶段进入稳定阶段之后我又做了两件事把它从一次性分析变成可定期运行的流程。第一件事是把整个流程写成函数链数据读取、清洗、特征构造、训练、输出分群画像每个环节一个函数用一份配置文件管理参数时间窗口天数、聚类数、异常值截尾分位数。这样每个月数据更新后跑一遍脚本就能得到最新分群。运营那边把输出结果接到报表的定时任务上分群结果就成了一个可以追踪的动态标签。第二件事是给每个用户打上分群标签回写到用户表里。这个动作很关键它把分析结果真正落到了运营系统里——群发邮件可以按标签圈选用户优惠券投放可以按标签定向发券商城首页的Banner也可以按标签做差异化展示。到这一步聚类分析才从我做了一个分析变成我上线了一个运营策略引擎。还要补一个关于K值稳定性的建议我建议不要只依赖单次聚类结果。电商用户的消费行为受大促活动影响很大双11前后的分群结果会明显漂移。我的做法是每月定期重算一次连续看三个月的分群迁移情况观察哪些用户在高价值群里持续待着、哪些从活跃群滑向了沉睡群。这种用户群迁移追踪比单次分群结果对运营的指导价值更大——你能看到每个群的流入流出找到驱动用户层级变化的真实原因。这个项目做完之后我又把同一套流程用在了另一个小额零售店铺上区别只在于特征里多加了最近一次参与活动距今天数聚类依然是K5。当时我最大的感受是电商用户聚类这件事难点从来不在算法的参数调整而在你怎么理解业务、怎么构造特征、怎么让结果被业务团队真正用起来。数据和算法只是工具分群背后的那群消费者才是这个项目真正要搞懂的对象。
阅读完成 · 觉得有帮助?