《模型不玄学》第9章 聚类是什么:让行为像的人自己抱成团
2026/9/20 12:41:23 网站建设 项目流程

第9章 聚类是什么:让行为像的人自己抱成团

小白一句话:聚类就是机器自己把"行为像"的用户归到一伙,你不用提前告诉它分成几类、每类长什么样——它只看特征,谁离得近就谁一伙。

前面第2章说过,本项目有两套模型。活跃度预测(监督)回答"未来 7 天回不回来",那是第 5 部分的主菜。这一章先讲另一套:行为分类(无监督)。它回答的是另一个问题——这群人里,谁和谁的行为风格是一类?

为什么需要这个?因为"活跃不活跃"和"行为是什么风格"是两码事。一个每天来领、五种任务都碰的人,和一个每周只来一次、只领一种任务的人,活跃度可能都不低,但行为画像天差地别。把这种"风格"摸清楚,既能单独用(给运营分群),也能喂给后面的活跃度模型当额外特征。而它最大的特点是:不需要标签。我们手头没有"这个用户属于哪类行为"的标准答案,就让机器自己从数据里找结构。

聚类的直觉:距离 = 行为像不像

聚类的前提只有一个:能把每个用户变成一串数字(特征向量)。这件事第7章已经做完了——每个用户到评分日为止,都有一份行为指纹(新近度、频率、持续性、趋势、偏好那些)。

有了这串数字,“两个用户行为像不像"就可以翻译成"他俩的向量离得近不近”。距离近 → 行为像 → 该一伙;距离远 → 行为不像 → 分开。

最常用的算法是K-Means,它的想法朴素到能一句话讲完:

先随便撒 k 个"中心点",把所有点分给最近的中心,然后挪中心到各堆的重心,再重新分,再挪中心……反复几轮,直到中心点不动了,分堆就定了。

就这么来回迭代,机器慢慢把空间切成几块,每块里的人彼此最像。

上手:用示例数据跑一个最简单的聚类

我们用第7章算好的行为指纹,先挑两个最直观的维度来看——全期活跃天数(来得多不多)和任务种类数(行为丰富不丰富)。把 57 个有充分历史的用户(评分日前零记录的冷启动用户先排除)画到这两维上,再让 K-Means 自动分 3 堆。

代码用第4章装好的 scikit-learn,几行就够:

importnumpyasnpfromsklearn.clusterimportKMeans# fps: 第7章算好的行为指纹列表;每人含 dall(全期活跃天数)、ntask(任务种类数) 等X2=np.array([[fp["dall"],fp["ntask"]]forfpinfps],dtype=float)km=KMeans(n_clusters=3,random_state=20260827,n_init=10).fit(X2)forcinrange(3):mem=[fp["uid"]forfp,ainzip(fps,km.labels_)ifa==c]cx,cy=km.cluster_centers_[c]print(f"簇{c}: 中心=({cx:.1f}天,{cy:.1f}类) 人数={len(mem)}")

跑出来的真实结果:

中心(全期天数, 种类数)人数这一堆的人大概什么样
簇 0(10.9 天, 5.0 类)24来得挺勤、五种任务都碰
簇 1(3.1 天, 2.2 类)20来得稀、只碰一两种任务
簇 2(19.7 天, 5.0 类)13几乎天天来、五种任务全碰

看这张表,机器干了件你肉眼也做得到、但 57 个人时懒得做的事:它把"几乎天天来且啥都领"的人(簇 2)、"来得中等且啥都领"的人(簇 0)、“来得稀且只领一两种"的人(簇 1)自动隔开了。没人告诉它"高频多任务”"低频少任务"这些词,它只看了数字就近乎还原了这些行为模式。

横轴是"全期活跃天数",纵轴是"任务种类数"。蓝色点(簇 0)和中绿点(簇 2)都集中在 y=5 附近,但它俩被横轴切成了"中频多任务"和"高频多任务"两堆;橙色点(簇 1)全在低区,y 值通常只有 1~3。黑色 X 是每个簇的中心。三堆几乎不打架,边界清楚——这就是机器按距离"抱团"的结果。

簇编号只是代号,不是等级

新手最容易犯的错,是看到"簇 0、簇 1、簇 2",顺手当成"弱、中、强"三等。这是错的。

K-Means 给簇编号,纯粹是"第一堆、第二堆、第三堆"的代号,编号大小跟强弱无关。上面表里簇 0 中心是 (10.9, 5.0)、簇 2 是 (19.7, 5.0)——簇 2 比簇 0 更活跃,但编号反而更大。如果把编号当等级,结论就反了。

所以无监督聚类产出的是"分群",不是"打分"。这堆人行为像、那堆人行为像,但哪一堆"好"哪一堆"差",模型不关心,也没资格关心——它根本没见过标签。这也是为什么本项目把"行为分类"和"活跃度预测"拆成两个模型(第2、3章讲过):分群告诉你"他是哪类人",预测才告诉你"他会不会回来",两件事不能混。

维度一多,就得先"把尺子拉平":标准化

刚才只用两维,天数和种类数都是十以内的小整数,尺度差不多,直接喂进去问题不大。但真实聚类用的是第7章那一整排特征:全期活跃天数顶多 22,总奖励金额却上百,趋势在 −3~+1 之间,偏好熵在 0~2.3 之间。

不处理的话,K-Means 算距离时会被"数值大的维度"牵着走——总奖励几百,轻轻一动就比天数差十几还大,天数、趋势这些小维度直接被淹没,聚类就变成"按花钱多少分堆"了,不是我们想要的"行为风格"。

解决办法是标准化:把每个特征都变成"均值 0、标准差 1",相当于把所有尺子拉到同一把刻度上再比距离。scikit-learn 里一行搞定:

fromsklearn.preprocessingimportStandardScaler keys=["recency","d7","d14","dall","longest","trend","ntask","top_share","entropy","amount"]raw=np.array([[fp[k]forkinkeys]forfpinfps],dtype=float)Xs=StandardScaler().fit_transform(raw)# 每列都变成均值0、标准差1

我们对标准化后的 10 维特征再跑一次 K-Means,这次分 5 堆(附件/04_行为聚类篇/behavior_cluster_intro.py里是同一段逻辑),结果很有意思:

人数中心(原始尺度,节选)这堆的行为风格
簇 05全期 1.2 天 / 1 种 / 主占比 1.0 / 熵 0极稀疏、只领一种(几乎冷启动边缘)
簇 110全期 12.1 天 / 5 种 / 趋势 +0.6 / 熵 2.3中高频、啥都领、还在涨
簇 215全期 3.7 天 / 2.7 种 / 趋势 0低频、只碰少数几种、持平
簇 315全期 10.5 天 / 4.9 种 / 趋势−1.8/ 熵 2.2中高频、啥都领、但在掉
簇 412全期 20.0 天 / 5 种 / 趋势 −0.2 / 熵 2.3近乎天天来、啥都领、稳

注意簇 1 和簇 3:都是"中高频、五种任务都碰",但簇 1 的趋势是 +0.6(在涨),簇 3 的趋势是 −1.8(在掉)。靠"全期天数"这一维,这两堆会被混在一起;加上"趋势"维度、标准化后一起看,机器就把"正在变凉的高频用户"单独挑出来了。这正是多特征 + 标准化的价值——它抓到了单看一个维度抓不到的结构。

这张图不是用原来的"天数/种类数"坐标了,而是把 10 维特征先标准化、再聚类,最后用 PCA 压缩到 2D 给你看分群结构。横纵轴(PCA-1/PCA-2)本身已经没有"天数"或"奖励"那么直观的含义,它只是帮你肉眼判断:5 个簇是不是各据一块、彼此分开。从图上看,橙色、蓝色、紫色、红色、绿色五坨点基本各自抱团,说明高维聚类确实切出了单看一两维切不出的细分结构。

(这 5 堆只是演示用 k=5,真实项目里 k 选几、每堆叫什么,是下一章"跑通行为聚类"要专门讲的。)

聚类不是只有 K-Means

K-Means 好懂好用,但它有脾气:得先指定分成几堆(k)、对"形状不规则的堆"不敏感、对异常点比较脆。真实项目里,行为分群也常用GMM(高斯混合模型)——它不光告诉你"归哪堆",还给你"属于每堆的概率",更适合行为有渐变、不好硬切的情况。本项目行为分类用的就是这一类思路。

不过对入门来说,先把 K-Means 的直觉吃透就够了:它本质上就是"按距离把像的人抱团",其余算法是在这个想法上补各种短板。

动手:自己看机器怎么分

打开附件/04_行为聚类篇/behavior_cluster_intro.py(依赖第4章的 numpy + scikit-learn),跑一遍:

python 附件/04_行为聚类篇/behavior_cluster_intro.py

你会看到和上面表格一致的簇中心和人数。然后做两件事,不用改算法也能体会到聚类的意思:

  1. 先把簇编号遮住,自己目测分 3 堆。看着 (全期天数, 种类数) 这两个数,你会怎么把 57 个人分成"高频多任务 / 中频多任务 / 低频少任务"?再和机器输出的簇对一下,是不是八九不离十?
  2. 想想"簇编号能当分数吗"。机器给簇 2 编了最大的号,但簇 2 只是"几乎天天来"那一堆。如果运营拿簇编号当"活跃等级"去发奖励,会发生什么?把你的答案和本章"簇编号无意义"那节对照一下。
  3. 打开生成的图,再和表格对一下。跑附件/04_行为聚类篇/behavior_cluster_viz.py会输出附件/04_行为聚类篇/behavior_cluster_2d.png附件/04_行为聚类篇/behavior_cluster_pca.png。先遮住图例,自己给三个色块各起一个人话名字(比如"几乎天天来、啥都领"),再对照上面表格里的簇中心,看你对不对得上。

把"聚类 = 按距离自动抱团、编号只是代号、多特征要先标准化"这三件事记牢,下一章就能顺着它把真实的行为分群跑通、再给每堆起上人话名字。


本章配套脚本:附件/04_行为聚类篇/behavior_cluster_intro.py(打印簇中心)和附件/04_行为聚类篇/behavior_cluster_viz.py(生成配图)。二者都基于 scikit-learn;所需的 numpy、scikit-learn、matplotlib 已在第4章附件/00_公共/requirements.txt中列出,环境搭建见第4章。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询