1. 项目逻辑与思路拆解
1.1 电商用户分析到底要解决什么问题
做电商数据分析这行久了你会发现一件事:老板嘴上说的“分析用户”,落到数据层面其实就三个问题——用户是谁、用户想要什么、用户什么时候会流失。这三个问题看着简单,但真要回答清楚,靠一堆平均指标根本办不到。比如“客单价200元”这种数字,掩盖了“一批人只买9.9包邮,另一批人每个月买上千”的天壤之别。
用户聚类解决的就是这个痛点:不跟你谈平均值,而是把用户分成不同的人群,让每群人内部足够相似、群体之间足够不同。这样一来,运营可以针对每一类人群做定向策略,而不是拿着同一套方案轰炸所有人。用Python做这件事,最大的好处是可以把数据处理、特征构建、聚类建模、可视化全部串在一条流水线里,改一个参数重跑一遍就行,不用在Excel和SPSS之间来回倒腾。
这个项目适合三类人参考:一是电商公司的数据分析师,想把“用户画像”从PPT落到实打实的分群结果;二是刚学Python机器学习的人,想找一个既不太难、又能直接应用到实际业务的数据集练手;三是做用户增长或CRM的运营,想用聚类结果反向指导自己的运营动作。下面我按自己实际做项目的思路,把从数据到分群结果再到业务策略的完整链路拆开讲。
1.2 为什么选聚类而不是简单打标签
很多人会问:用户分层不是有现成模型吗?比如RFM评分、生命周期模型、AARRR漏斗,为什么还要上聚类?
我的回答是:RFM模型当然有用,它作为“打分框架”很好,但它的局限性也很明显。RFM三个维度是人工设定的,每个维度的阈值切分带有很多主观判断——消费次数大于几次算高频?客单价大于多少算高客单?这些阈值在不同类目的电商平台之间差异巨大,做美妆的和做3C的,用户行为模式完全是两码事。
聚类算法不需要你预先定规则,它靠数据自身的学习来发现人群结构。我举个生活化的例子:你想把一堆水果分类,规则法是你先规定“红色且圆的算苹果、黄色且弯的算香蕉”,然后一个个套;聚类法是让算法自动发现“有一堆东西颜色偏红、形状偏圆、口感偏脆,它们天然聚在一起”,你再来给这群东西起名。后者更适合探索性的用户分析,因为你事先并不知道你的用户到底有几类、每类长什么样。
从项目实操角度看,先用聚类做探索,再用聚类结果去校准运营规则,比拍脑袋定阈值要科学得多。这也是我推荐想做用户分群的团队,先跑一遍聚类再谈规则的原因。
1.3 技术选型:为什么是Python全家桶
做这个项目我用的核心工具是Python的pandas、scikit-learn和matplotlib/seaborn这三件套,不需要装任何额外重的平台。选型的原因很直接:
第一,pandas处理表格数据是事实标准。电商订单数据最常见的形态就是一张大宽表,字段有几十个,pandas的groupby、merge、pivot_table可以在一两个小时内完成所有清洗和特征构建。
第二,scikit-learn的聚类算法实现稳定且接口统一。KMeans、层次聚类、DBSCAN、GaussianMixture这些都是几行代码的事,而且轮廓系数、Calinski-Harabasz指数等评估指标也都封装好了,做对比实验非常方便。
第三,可视化的生态成熟。聚类结果最终要给业务看,画不出图一切白搭。matplotlib画散点图和雷达图,seaborn画分布图和热力图,基本能满足分群报告的所有需求。
下面是这个项目我用到的工具清单,以及各自的用途,方便你对照准备环境:
| 工具/库 | 用途 | 备注 |
|---|---|---|
| pandas | 数据读取、清洗、聚合、透视 | 必修,处理表格数据的主力 |
| numpy | 数组运算、向量化计算 | pandas的底层依赖,特征工程常用 |
| scikit-learn | KMeans、层次聚类、DBSCAN、标准化、PCA | 聚类建模和评估的核心库 |
| matplotlib | 基础绘图 | 散点图、轮廓系数图、肘部图 |
| seaborn | 统计可视化 | 分布图、热力图,颜色更美观 |
| scipy | 层次聚类的树状图函数 | 在scipy.cluster.hierarchy里 |
环境方面,建议直接用Anaconda或Python 3.9以上版本,装好后执行pip install pandas numpy scikit-learn matplotlib seaborn scipy即可。我自己的实测环境是Python 3.10 + scikit-learn 1.3.x,下面的代码在这个版本组合下跑通没有问题。
2. 数据处理与特征工程:聚类效果的上限在这里
2.1 数据准备:拿什么数据、长什么样
做用户聚类,第一个坑就是数据源乱。很多新人拿到订单表就开始跑模型,结果特征一塌糊涂。我先说清楚:至少需要三张表的关联信息——用户基础信息表(user_id、注册时间、城市、性别等)、订单表(user_id、订单金额、下单时间、付款状态)、行为表(浏览/加购/收藏记录)。如果只有订单表,也能做,但特征维度会少很多。
我这次项目用的是模拟电商订单数据,约1万条订单记录、3000个用户,时间跨度6个月。订单表核心字段包括:order_id、user_id、order_amount、pay_amount、order_date、pay_time、商品类目。行为表包含:user_id、行为类型(浏览/加购/收藏/下单)、行为时间。
需要特别提醒一点:做用户分析一定要先明确分析口径。比如退款订单要不要算进消费金额?未付款订单算不算行为?我自己的做法是:聚类建模时只纳入“已付款且未退款”的订单,行为数据全部保留但分不同权重处理。这个口径问题如果你不在一开始定义清楚,后面出的所有结论都会被业务挑战。
2.2 数据清洗:脏数据会让聚类结果彻底跑偏
聚类算法对数据质量极其敏感,一个极端值就能把KMeans的簇中心拽走。我实际处理中的清洗顺序是:
先去重。订单号重复的直接保留最新一条;用户ID重复的检查是否是同一人多设备注册,如果是,以最早注册时间为准合并。
再处理缺失值。pay_amount为空的大部分是未支付订单,建模时直接过滤;城市、性别这类字段缺失比例如果超过30%,建议直接丢弃该字段,不足30%的用众数填充。
最后是异常值处理。我见过客单价几十万的订单(可能是B2B批发或者内部测试),也有大量0.01元的“刷单”订单。这些不处理的话,聚类会把极端用户单独劈成一类,业务上根本没法解释。处理方法是先按分位数看一下分布——以99.5分位数为界限做截断,把超过阈值的订单金额缩尾到阈值本身,而不是直接删除;对于0.01元的异常订单,结合支付时间判断是否为测试订单,是测试单就删掉。
清洗完的数据,需要沉淀成一张“用户宽表”。这一步是后期所有分析的基石,我通常会把宽表保存成csv或者parquet,后续特征工程直接在宽表上追加列。宽表结构示例如下:
| user_id | 注册日期 | 城市 | 总订单数 | 总消费金额 | 最近消费日期 | 平均客单价 |
|---|
2.3 特征工程:RFM的升级版和扩展特征
用户聚类最经典的特征组合是RFM,即Recency(最近一次消费距今天数)、Frequency(消费频率)、Monetary(消费金额)。但只用这三个特征做聚类,结果颗粒度太粗,业务上很难差异化。我在这次项目里做了两个层次的扩展:
第一层是RFM的精细化。Recency不只用“最近一次消费距今天数”,还可以加“平均消费间隔”;Frequency不只看订单数,还看“活跃月份数”——比如一个用户虽然总共下单20次,但都集中在1个月,和分散在6个月里,价值完全不同;Monetary不只看总额,还要看“平均每单金额”和“最大单笔金额”,后者能识别出“偶尔买个大件”的用户。
第二层是行为特征的补充。包括浏览深度(总浏览商品数/总下单数)、加购率(加购次数/浏览次数)、收藏率、复购间隔的波动性等。这些特征反映了用户的决策习惯和购买意愿强度。
我自己构建的核心特征列表如下:
- recency_days:最近一次消费距统计日期的天数
- total_orders:有效订单总数
- total_amount:有效消费总金额
- avg_order_value:平均客单价
- max_order_amount:最大单笔订单金额
- active_months:有下单行为的月份数
- avg_browse_to_cart:浏览到加购的转化率
- cart_to_order:加购到下单的转化率
- browse_depth:总浏览商品数/总订单数
- return_rate:退货率(如果有退款数据)
这里要重点强调:特征不是越多越好。特征太多会引入噪声,而且聚类在高维空间里会遇到“维度灾难”——距离计算会变得很不稳定。我的经验是特征数量控制在8到12个之间,且强相关特征要删掉一个。比如total_amount和avg_order_value*total_orders是强相关的,保留total_amount即可。
2.4 特征标准化:不做标准化的聚类等于白做
聚类算法全部基于距离计算。你的特征单位如果一个是“元”(金额),一个是“次”(订单数),一个是“天”(间隔天数),量级差异之大,会让金额特征完全主导距离计算,订单数、间隔天数几乎不起作用。
处理方法有两种:StandardScaler(标准化到均值为0、方差为1)和MinMaxScaler(缩放到0到1之间)。KMeans这类基于欧氏距离的算法,我推荐用StandardScaler,它对异常值的容忍度稍好一些。如果你的数据分布极度偏斜(比如消费金额长尾严重),可以先做log1p变换再标准化,这样效果比直接标准化好得多。
另外我强烈建议在聚类之前先做PCA降维。原因有两个:一是降维后可以把聚类结果可视化(二维或三维散点图),业务能看清你的分群;二是PCA可以在保留主要信息的同时去掉噪声。我实际做的结果是:12个特征降到6个主成分,累计方差贡献率约85%,聚类轮廓系数反而比用全特征时更高了。这印证了一件事——对聚类来说,特征并不是越多越好。
3. 聚类算法选型与关键代码实现
3.1 KMeans:首选,但K值怎么定
KMeans是用户聚类最常用的算法,原理简单:随机初始化K个中心点,迭代地把样本划分到最近的中心点所在簇,然后重新计算簇中心,直到收敛。这个算法的优点是快、可解释性强,缺点是对初始中心敏感、只能发现“球形”簇。
K值的选择是整个项目最关键的决定。我用的方法是肘部法则加轮廓系数双验证。肘部法则看的是“簇内误差平方和(SSE)”随K值变化的曲线,曲线从陡降到平缓的拐点处就是合适的K;轮廓系数衡量的是样本与自身簇内点的相似度和与最近邻簇内点的相似度的差值,取值范围从-1到1,越大越好。
具体实现代码如下:
from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score import matplotlib.pyplot as plt # X_scaled 是标准化并降维后的特征矩阵 sse = [] silhouette_scores = [] K_range = range(2, 11) for k in K_range: km = KMeans(n_clusters=k, random_state=42, n_init=10) km.fit(X_scaled) sse.append(km.inertia_) silhouette_scores.append(silhouette_score(X_scaled, km.labels_)) # 绘制肘部图 plt.figure(figsize=(10, 4)) plt.subplot(1, 2, 1) plt.plot(K_range, sse, marker='o') plt.xlabel('K') plt.ylabel('SSE') plt.title('肘部法则') plt.subplot(1, 2, 2) plt.plot(K_range, silhouette_scores, marker='o') plt.xlabel('K') plt.ylabel('轮廓系数') plt.title('轮廓系数') plt.tight_layout() plt.show()我在这次项目中跑出来的结果是:SSE曲线在K=4和K=5之间出现明显拐点,轮廓系数在K=4时达到峰值0.38左右,随后下降。结合业务可解释性,最终选定K=4,即四类用户群。这里要说句实在话:轮廓系数0.3-0.4在电商用户数据的场景下已经算不错了,因为用户行为数据本身噪声大,期望0.7以上的高轮廓系数是不现实的。
3.2 层次聚类:看树状图比看散点图更直观
KMeans能出结果,但它不能告诉你“为什么分成4类是对的”。层次聚类(Hierarchical Clustering)补充了这个能力——它输出的树状图(Dendrogram)可以直观展示用户群之间的从属关系和合并过程,非常适合做探索性分析阶段的可视化解释。
代码实现如下:
from scipy.cluster.hierarchy import dendrogram, linkage from scipy.cluster.hierarchy import fcluster import matplotlib.pyplot as plt # 计算层次聚类链接矩阵 Z = linkage(X_scaled, method='ward') # 绘制树状图,只显示最后30个合并点,避免图片过于拥挤 plt.figure(figsize=(12, 6)) dendrogram(Z, truncate_mode='lastp', p=30, leaf_rotation=90) plt.title('层次聚类树状图(截断版)') plt.xlabel('样本序号') plt.ylabel('距离') plt.show() # 在距离阈值处切割得到4个簇 labels_hier = fcluster(Z, t=4, criterion='maxclust')看树状图有一个技巧:找“长垂直线”的位置。树状图里越长的垂直线,代表合并的两个簇之间的距离越大,说明这个分裂点越可靠。如果某条长线的下方刚好能分出4个分支,说明分成4类在结构上是有依据的。我在项目中用ward方法是因为它倾向于生成大小比较均衡的簇,实测也比single、complete方法更适合电商用户这种连续型特征数据。
3.3 DBSCAN:处理“不忠诚用户”的利器
KMeans默认会把每个用户都分到某一个簇里,哪怕这个人只买过一次9.9元商品,也会被硬塞进去。这带来一个问题:异常用户(刷单号、一次性游客)会污染正常簇的结构。
DBSCAN算法的思路完全不同,它根据样本密度聚类,能把低密度区域的样本直接判定为“噪声点”(label=-1)。这在实际业务中太有用了——那些无法被归类的用户,往往就是你需要单独处理的异常或者流失边缘用户。
from sklearn.cluster import DBSCAN from sklearn.neighbors import NearestNeighbors # 先用K-距离图确定eps参数 neigh = NearestNeighbors(n_neighbors=5) neigh.fit(X_scaled) distances, _ = neigh.kneighbors(X_scaled) distances = sorted(distances[:, -1]) # 绘制排序后的第5近邻距离曲线 plt.plot(distances) plt.xlabel('样本序号') plt.ylabel('第5近邻距离') plt.show()K-距离图里曲线急剧上升的“拐点”对应的距离,就是合理的eps取值。我在实验里用eps=1.2、min_samples=10,结果识别出约6%的噪声用户。这些用户大多是只注册没下单、或者半年内只下过一次单后再无行为的“僵尸用户”。
如果只看KMeans结果,这6%的用户会被分到低频低金额簇里凑数;而用DBSCAN把它们单独标记出来后,再做KMeans,剩余用户的轮廓系数从0.38提升到了0.44。这就是一个很典型的算法配合用法:先用DBSCAN剔除噪声,再对有效用户跑KMeans找细分结构。
3.4 聚类评估:不要只盯轮廓系数
轮廓系数是最常用的聚类评估指标,但只看它绝对不够。我常用的还有Calinski-Harabasz指数(CH指数)和Davies-Bouldin指数(DB指数)。CH指数是簇间离散度与簇内离散度的比值,越大越好;DB指数是簇内平均距离与簇间距离的比值,越小越好。
如果在做选型对比,我的建议是综合三个指标一起看:
| 指标 | 方向 | 本次项目实测值(K=4) | 解读 |
|---|---|---|---|
| 轮廓系数 | 越大越好 | 0.38 | 簇间分离度尚可 |
| CH指数 | 越大越好 | 486.2 | 簇间差异显著 |
| DB指数 | 越小越好 | 1.21 | 簇内聚合度可以接受 |
更重要的是业务口径的验证。聚类最终是要给运营用的,你分出来的每一类用户,都必须能用一句话讲清楚“这群人是谁、有什么特征、该怎么对待”。如果一个簇解释不清楚,哪怕指标再好都是没用的。
3.5 完整核心代码:从宽表到分群结果
下面是一段我在项目中实际使用的核心代码,整合了标准化、降维、聚类和结果回写。你直接按这个骨架改自己的数据字段就能跑通:
import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA from sklearn.cluster import KMeans # 1. 读取用户宽表 df = pd.read_csv('user_wide_table.csv') # 2. 选择特征列 feature_cols = ['recency_days', 'total_orders', 'total_amount', 'avg_order_value', 'max_order_amount', 'active_months', 'browse_depth', 'cart_to_order'] X = df[feature_cols].copy() # 3. 对严重偏斜的金额特征做log变换 for col in ['total_amount', 'avg_order_value', 'max_order_amount']: X[col] = np.log1p(X[col]) # 4. 标准化 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 5. PCA降维到6维 pca = PCA(n_components=6, random_state=42) X_pca = pca.fit_transform(X_scaled) # 6. KMeans聚类,K=4 kmeans = KMeans(n_clusters=4, random_state=42, n_init=10) df['cluster'] = kmeans.fit_predict(X_pca) # 7. 查看每个簇的样本量 print(df['cluster'].value_counts()) # 8. 分簇统计特征均值,用于后续人群解读 cluster_profile = df.groupby('cluster')[feature_cols].mean() print(cluster_profile.round(2))跑完之后,df表里每一行用户都多了一个cluster列,值从0到3。接下来要做的就是把特征均值还原成原始业务含义(比如log金额要exp回去),去给每个簇写用户画像。
4. 聚类结果解读与业务落地
4.1 用户分群画像:四类人群长什么样
我这次项目跑出来的四类人群,特征差异非常明显,我直接按业务叫法命名:
- 簇0:高价值忠诚用户,占12%。总消费金额、平均客单价、最大单笔金额都是最高的,活跃月份数接近满值,最近消费距今天数很短。这群人是平台的利润核心。
- 簇1:潜力成长用户,占32%。下单频率不低,但客单价偏低,浏览深度大、加购率高,说明兴趣浓厚但是价格敏感,需要靠活动和推荐转化。
- 簇2:价格敏感型用户,占41%。消费金额低、客单价低、订单数少,但比簇3强一点的是他们还有近期消费。这群人数量最大,是拉活和复购激励的重点对象。
- 簇3:流失风险用户,占15%。最近消费距今天数很长,活跃月份数极少,平均消费金额曾经不低(历史消费说明之前有购买力),但已经很久没有动静。这群人是召回的重点。
这里有个很重要的认知:聚类算法的分群命名,不能算法跑完就随便贴标签,而是要把每个簇的原始特征值和全量平均值做对比,找出“显著偏高/偏低”的特征来定义人群。我在实际操作中会输出每个簇的Z-score表——特征值与均值差几个标准差,一眼就能看出人群核心特征,也方便跟业务方对齐描述口径。
4.2 基于人群特征制定差异化运营策略
聚类结果不能停在报表层,它必须能转译成运营动作。我对这四类用户分别设计了不同的策略逻辑:
高价值忠诚用户的运营目标是“维护和拉升”。比如建立专属客服群提供一对一服务、设计高阶会员权益、邀请参与新品内测,让这批头部用户感受到尊贵感。同时关注他们的购买品类迁移,及时推送他们可能感兴趣的高客单新品。
潜力成长用户的运营目标是“提客单”。既然他们兴趣浓厚但价格敏感,就用组合优惠券、满减活动、限时折扣来促进他们买更多。还可以通过“加价购”“第二件半价”这类手段提高客单。关键动作是识别他们高频浏览但未下单的商品,做精准定向推送。
价格敏感用户的运营目标是“促活跃”。这批用户基数最大,即使人均贡献不高,只要活跃度提升,整体GMV也会有明显改善。可以用签到领积分、低价秒杀、运费减免这类轻量激励来拉回流。
流失风险用户的运营目标是“召回”。因为他们历史消费能力不弱,值得做一次精准召回。方式包括短信发送限时专属券、邮件追加强召回折扣、在App内弹窗推送老用户回归活动。如果召回失败,就把他们转入沉默用户池,减少无效触达。
4.3 可视化:让分群结果自己会说话
聚类报告要能服人,可视化是关键。我做分群展示时会画三张图:PCA降维后的散点图、各簇特征的雷达图、各簇在各特征上的均值对比柱状图。
散点图展示分群效果,一眼能看出簇之间分离的情况;雷达图展示人群特征轮廓,方便跟业务方讲解人群差异;柱状图用于对比同一特征下不同簇的表现,定位“谁高谁低”。
import matplotlib.pyplot as plt import seaborn as sns # 将PCA结果和簇标签拼成一个DataFrame用于绘图 df_viz = pd.DataFrame(X_pca[:, :2], columns=['PC1', 'PC2']) df_viz['cluster'] = df['cluster'].values # 散点图 plt.figure(figsize=(10, 6)) sns.scatterplot(data=df_viz, x='PC1', y='PC2', hue='cluster', palette='Set2', alpha=0.6) plt.title('PCA降维后的用户聚类分布') plt.show() # 雷达图:用各簇标准化后的特征均值表示 from math import pi features_mean = df.groupby('cluster')[feature_cols].mean() # 对特征均值做MinMax缩放便于在0-1区间绘制 radar_df = (features_mean - features_mean.min()) / (features_mean.max() - features_mean.min()) categories = radar_df.columns.tolist() N = len(categories) angles = [n / float(N) * 2 * pi for n in range(N)] angles += angles[:1] fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True)) for i, cluster_id in enumerate(radar_df.index): values = radar_df.loc[cluster_id].values.flatten().tolist() values += values[:1] ax.plot(angles, values, linewidth=2, label=f'Cluster {cluster_id}') ax.fill(angles, values, alpha=0.1) ax.set_xticks(angles[:-1]) ax.set_xticklabels(categories, size=9) ax.legend(loc='upper right', bbox_to_anchor=(1.2, 1.1)) plt.title('各聚类群体特征雷达图') plt.show()雷达图有个明显的优点:四个簇的特征轮廓如果形状差异大,说明分群结果有效;如果形状都差不多,那就要考虑是不是特征没选好、或者K值选大了。这也是我每次聚类后必看雷达图的原因。
5. 常见问题与排查技巧实录
5.1 K值怎么选才靠谱
选错K值是新手最常犯的错误。我见过有人直接拍脑袋定K=5,结果跑出来有两簇几乎重合,业务根本没法区分。我的做法是肘部法则、轮廓系数、树状图三个手段交叉验证,并且每一轮都要回到业务问自己一个问题:这个簇能否用一句话说清特征。
如果你跑完发现两簇特征均值几乎一致,说明K选大了,应该合并;如果某一簇样本量太少(小于5%),说明K选大了或者数据里本身存在明显离群点;如果某个簇覆盖了70%以上的样本,说明K选小了,内部应该还能细分。这些判断指标比单纯的统计量更实用。
5.2 数据偏斜严重怎么办
电商数据几乎必然偏斜:少数用户的消费占了大头。如果你直接对原始金额跑KMeans,高价值用户会被单独劈成一簇,剩下的人挤成一坨。这种情况下先从数据层面解决:对金额类特征做log1p变换,让长尾收拢;再做分位数截断处理掉极端值;最后考虑用稳健标准化(RobustScaler)替代StandardScaler——它基于中位数和四分位距,对异常值不那么敏感。
我在多个电商数据集上实测过,log变换+RobustScaler的组合,在处理消费金额极端异质性上效果非常稳定。这应该是你的默认组合,而不是普通标准化。
5.3 聚类结果每次运行都不一样
KMeans的初始中心是随机的,所以每次运行结果可能略有不同。这不是bug,是算法特性。解决方式有两个:第一,设置random_state固定随机种子,保证结果可复现;第二,设置n_init=10甚至更多,让算法跑多次取最优结果,这比单次运行更稳定。
我在代码里用的是random_state=42、n_init=10,这样团队其他人复跑我的代码时能得到一模一样的簇标签,避免“我跑出来和你的不一样”这种扯皮。
5.4 标准化用哪种:StandardScaler还是MinMaxScaler
关于这个问题我直接给结论:做KMeans聚类,优先用StandardScaler;如果后续要配合DBSCAN,可以换成MinMaxScaler。原因是DBSCAN的eps参数直接对应距离阈值,MinMaxScaler把数据缩放到0到1之间后,eps的取值范围更可控、更好调参。StandardScaler缩出来的数据没有固定边界,eps找起来全靠K-距离图。
5.5 业务落地时的经典坑
我踩过最大的坑是:聚类结果直接扔给运营,运营说“我看不懂”。后来我明白了一个道理——聚类模型是数据团队内部的一个中间产物,它必须被“翻译”成业务语言。具体做法是给每一簇用户起一个人格化的名字,比如“深夜剁手党”“比价纠结症”“客单担当”“沉睡大户”,配合一页纸的特征说明、典型用户案例和运营建议。只有这样,运营才真正看得进去、用得起来。
另外一个坑是时间口径。用户聚类是时效性很强的分析,6个月前的聚类结果放到今天,人群可能已经迁移了。我建议按月或者按季度重新跑聚类,同时监控各簇占比的波动。如果某簇占比突然大幅变化,先排查数据口径是否变动,再考虑是不是业务策略导致的人群迁移。
5.6 聚类失败怎么排查:一个实用速查表
如果你跑完的结果明显不合理,可以从下面几个方向去查:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 某个簇特征均值全部偏低 | 极端值未处理,算法被带偏 | 检查金额分位数分布,做log和截断 |
| 两个簇特征均值几乎一致 | K值偏大,或特征区分度不足 | 降低K值,重新检查特征列表 |
| 轮廓系数极低(<0.2) | 特征没标准化,或噪声过大 | 确认是否使用StandardScaler,用DBSCAN剔除噪声 |
| 聚类结果无法解释 | 特征太多或太冗余 | 用PCA降维,删掉强相关特征 |
| 每次运行结果不一样 | 未设随机种子、n_init过小 | 固定random_state,调大n_init |
这张表帮你节省了大量试错时间。很多情况下,问题根本不在聚类算法本身,而在前面的数据处理和特征工程环节。
写在最后的一点体会
这个项目做下来的感觉是:用户聚类技术本身不复杂,真正花时间的是业务理解和特征工程。KMeans的代码几行就写完了,但为了让这四类用户能落到运营动作上,我在特征设计、数据清洗和结果解释上花的精力比建模多出好几倍。
最后分享一个小技巧:给每一类用户写一个“虚拟人物小传”。比如簇1写“小美,25岁,刚工作两年,喜欢收藏加购但总等打折再买,每周至少浏览两次App,最近一次下单是3天前。”这个小传会让整个分群报告变得鲜活,业务方接受度也会高很多。你如果能坚持把聚类结果做成这种“有人味”的交付物,这个项目的价值就已经超越了一份技术报告,变成了真正驱动业务决策的数据资产。