☰
SAS PROC FASTCLUS实现K-均值聚类:从数据清洗到客户分群落地
2026/10/15 13:30:52 网站建设 项目流程

先说个不算冷的知识:很多人跑聚类分析,第一反应是用Python调库,但在企业级报表和分析项目里,SAS的PROC FASTCLUS才是真正被市场、风控、运营团队用了十几年的稳路子。它跑K-均值聚类的速度、结果的稳健性、以及和后续评分建模的衔接,都不是“玩具代码”能比的。这篇文章就围绕SAS里最常用也最容易踩坑的K-均值聚类展开,完整梳理从数据预处理到聚类结果落地的全过程。

如果你手里正好有一批客户行为数据、店铺经营数据,或者任何需要“分群打分”的连续变量数据,而且想用SAS把它跑成一个能交给业务方的分析结论,那么这篇文章基本可以当作一份操作手册来用。

1. 为什么把K-均值当成客户分群的默认方案

1.1 K-均值到底在做什么

K-均值聚类的核心逻辑可以浓缩成一句话:把n个样本分到K个组里,使得每个样本到它所在组中心点的距离平方和最小。这个目标听起来很简单,但实际执行过程是反复迭代的:先随机或按规则选K个初始中心,把每个样本归到最近的中心,再根据归组后的样本重新计算中心,然后再归组、再算中心,直到中心点不再明显移动。

用大白话打个比方:就好比你要把一屋子的杂物分成几堆,一开始随手在房间不同角落放了几个箱子,把所有东西放到最近的箱子里,然后重新调整箱子的位置,让每个箱子正好是它那堆东西的“重心”,再重新分一次,反复几次后,每个箱子里的东西就越来越像了。

这个算法的价值在于它不需要人为标注“谁属于哪类”,完全靠数据自身的分布结构发现问题。做营销分析的时候,我们不知道客户该分红黄蓝几类,但K-均值可以根据消费金额、购买频次、活跃天数这些变量,自动把客户挤出几个相对紧凑的群体,每个群体内部特征相似,群体之间差异明显。

在SAS里,这个功能主要由PROC FASTCLUS承担。很多人习惯把PROC CLUSTER和PROC FASTCLUS混着说,其实两者定位不同:PROC CLUSTER更适合小样本、需要系统聚类谱系图的场景,你还能从中画出树状图;而PROC FASTCLUS专门为大数据量优化,采用的算法本质是K-均值的快速近似,它先把数据扫描一遍,选出若干有代表性的种子点,再做迭代更新。样本量达到几十万、上百万时,PROC FASTCLUS仍能保持很好的效率,这也是它在信贷、零售、电信行业被广泛使用的原因。

1.2 为什么营销分析社区里更认SAS

我不是说Python不行。Python生态确实灵活,但你只要在银行、保险、大型零售公司待过就会明白:项目交付要的是可审计、可复现、可交接的流程。SAS程序天然是过程化的,每一步做了什么、用什么参数、产生了什么数据集,都清清楚楚写在代码里,业务团队和合规团队要审核时非常方便。

另外,SAS的PROC FASTCLUS在执行效率上确实有优势。它默认采用“先选种子、再迭代”的两阶段策略,并不需要对所有样本做多次全量距离计算,在超大样本场景下比常规的K-均值实现快不少。我帮某大型零售项目处理过几百万条会员交易记录,PROC FASTCLUS跑一次聚类大约几十秒,而同样的数据在本地Python脚本里跑,耗时可能是它的好几倍,更不用说内存占用上的差异。

当然,速度不是选择SAS的唯一理由。更关键的是,SAS的聚类输出与后续的PROC DISCRIM、PROC LOGISTIC等过程衔接得非常丝滑。聚类结果可以作为分类标签,直接丢进判别分析验证分类效果,也可以合并回原始宽表用于后续建模,整个链路都在同一套代码框架内完成,不用到处导数据。

1.3 使用K-均值前必须想清楚的数据条件

在打开代码编辑器之前,我需要你先确认手里的数据适不适合做K-均值。第一个硬条件:变量必须是连续型或近似连续的数值变量。你的年龄、月收入、年内消费金额、活跃天数、平均客单价,这些都没问题;但性别、城市等级、支付渠道这种无序类别变量,直接放进PROC FASTCLUS会制造灾难——算法会按1、2、3的数字大小去计算“距离”,而数字编号本身不代表实际距离。

如果类别变量确实很重要,通常的做法是转成虚拟变量后再参与聚类。另一个更稳妥的折中方案是先对类别变量做对应分析或编码,再把它合并进连续变量集。总之,不要让算法去理解“1代表男、2代表女、3代表未知”这种语义信息,它理解不了。

第二个条件:变量必须做标准化处理。K-均值依赖欧氏距离,如果收入以“元”为单位是五位数的量级,活跃天数只有几十,消费笔数只是个位数,那么距离计算基本被收入这一个变量主导,其他变量形同虚设。后面会有专门一节讲怎么标准化。

第三个容易忽视的问题:离群值。K-均值对离群值异常敏感,因为它计算的每一个中心点都是组内样本的算术平均,一两个极端值就能把中心点拉偏,甚至让聚类结果彻底变形。建模前不处理离群值,聚类结果往往只能体现“离群点被孤立”,而不是真正的群体结构。

2. 建模前先把数据整干净:标准化、去离群、降冗余

2.1 数据清洗的三个常规步骤

这部分听起来像废话,但真正动手时最容易被跳过。准备聚类数据集,我一般按三步走。

第一步是缺失值处理。PROC FASTCLUS默认会删除所有包含缺失值的观测,如果你有几万行数据而关键变量缺失率只有2%,直接删掉问题不大;但如果是30%的缺失率,那就不能简单删除,否则留下的样本会偏向“数据完整的人群”,聚类结果失真。实际项目里,对于连续变量,我会先用PROC STDIZE或PROC EXPAND做插补,或者至少用该变量的中位数填充,然后再进入标准化流程。

第二步是去重。这里要特别小心“重复样本”的概念,它不只是完全相同的ID重复出现,还包括所有参与聚类的变量取值完全一致的记录。你觉得两条记录即使ID不同,只要金额、频次、活跃天数一模一样,就可以当成重复样本?恰恰是这种记录会在后面聚类时捣乱。K-均值按点到中心的距离分组,如果同一坐标点上有大量样本堆积,这个坐标点会被算法当成一个天然的中心点,导致产生一个“看似存在其实只是数据重复造成的伪簇”。我在实际项目里见过一次:某会员宽表因为多源数据重复合并,同一个会员生成了两三条一模一样的记录,聚类结果里莫名其妙多出一个“每天登录、从不购买”的簇,后来核查才发现是重复记录堆出来的。

第三步是确认变量类型。参与聚类的所有数值变量最好都确认是数值格式,而不是字符格式。用PROC CONTENTS看一遍数据结构,检查每个变量的类型与长度,这个习惯能帮你避免后续SAS报错或者结果里出现莫名其妙的分组。

2.2 标准化的正确姿势:PROC STDIZE

标准化看似简单,但在SAS里有一个容易被忽略的选择题:到底该用默认的均值-标准差法,还是用更稳健的中位数-绝对中位差法?

默认情况下,PROC STDIZE的METHOD=STD会按照均值0、标准差1的思路来处理数据。这个方法在数据分布比较对称时没问题,可一旦变量是右偏分布,比如“消费金额”这种数据,绝大多数人花得少、极少数人花得多,均值会被极端值拉高,标准化后大量正常样本会挤在负数区域,距离计算依然被极端值影响。

如果你想更稳健一点,可以改用METHOD=MEDIAN或者METHOD=ABW,它们分别基于中位数和加权绝对中位差做标准化,对离群值没有那么敏感。实际项目中我没有一成不变地全用METHOD=STD,而是先用PROC UNIVARIATE画出分布,如果几个关键变量明显偏态,就先做对数变换,再做标准化。

下面是一段同时完成缺失值插补与标准化的参考代码:

proc stdize data=work.cust_raw out=work.cust_std method=std reponly; var age income spend_freq active_days; run;

如果我只想填充缺失值、暂时不标准化,就用reponly选项先把缺失值替换成均值或中位数,再在下一步处理。这个思路很实用:把“缺值填充”和“尺度缩放”拆成两步,方便排查每一步产生的变化。

2.3 离群值处理:不要让一个超级用户毁掉整个聚类

离群值对K-均值是致命的。你可以这么理解:K-均值聚类的每一类中心都是组内样本的算术平均,一个消费金额高达几百万的VIP客户,可能会把某个簇的中心拉到远远偏离普通客户的位置,导致原本应该聚在一起的普通客户被强制分开。

对离群值处理,我推荐的组合拳是:先看分布,再考虑截尾,而不是粗暴地把超过三倍标准差的值全部删除。金融、零售数据里,高端用户本身就是重要的分析对象,你反而需要识别他们,不能因为离群就把他们扔掉。

我通常用PROC UNIVARIATE看每个变量的P1、P99分位数,然后结合业务逻辑决定是否做WINSORIZE,也就是把超过P99的值替换成P99,低于P1的值替换成P1。这个方法能保留样本数量,同时削弱极值对中心点的影响。如果某个变量出现多个离群点且看起来不是数据错误,我还会额外生成一个“是否高价值用户”的标识变量,单独聚类或作为辅助变量参与分群,而不是让这些离群点把整体结构带偏。

2.4 变量冗余问题:同样的信息别喂两遍

做聚类分析时,分析师经常犯一个错:把高度相关的变量一股脑全塞进去。比如“月消费金额”“年消费金额”“总消费金额”其实是同一个信息的不同尺度,三个变量同时参与距离计算,相当于消费金额这个维度在欧氏距离里被放大了三倍。整个聚类结果看起来好像很均衡,实际就是被消费金额一个维度绑架了。

我的做法是先跑一次PROC CORR看相关系数矩阵。两个变量相关系数超过0.8,建议只保留一个业务解释最直观的。如果保留多个,还需要考虑是否对变量先做一次主成分分析降维。

不过这里有个度的问题。变量也不是越少越好。变量太少,聚类结果会缺少可解释的区分度;变量太多,又会出现“维度灾难”,样本之间的距离都趋于相同,聚类失去意义。经验上,K-均值聚类的变量控制在5到15个之间比较理想,具体还要看样本量和业务需求。样本量在几万级别时,10个左右的变量完全够用。

3. PROC FASTCLUS 实战:从一行代码到完整聚类

3.1 最小可运行代码与逐行解释

数据清理和标准化都搞定之后,K-均值部分代码其实非常短。下面是一段最常用的写法:

proc fastclus data=work.cust_std out=work.cust_cluster maxclusters=5 maxiter=50 seed=12345 outstat=work.cluster_stats mean=var; var age income spend_freq active_days; run;

简单拆解一下:

  • DATA=指定输入标准化后的数据集;
  • OUT=指定聚类结果输出集,原始变量和预测的簇编号都会保留在这个数据集里;
  • MAXCLUSTERS=5告诉SAS最多分成5类,这并不等于自动选定为5类,它只是允许最大5类;
  • MAXITER=50是最大迭代次数,防止算法迟迟不收敛白白耗时间;
  • SEED=12345用于控制初始种子的选取,指定这个值后,每次运行结果完全可复现。这一点做项目交接时非常关键;
  • OUTSTAT=输出聚类统计量,后面看每个簇的均值、标准差、簇间方差占比都靠它;
  • VAR后面列出参与聚类的变量。

很多SAS版本里,PROC FASTCLUS默认打印一张“Cluster Summary”表,里面包含每个簇的频率、最大距离、最小距离、簇内均方根距离等。运行结束后,你可以直接去OUT=生成的数据集里查看新生成的CLUSTER变量,它从1到K编号,每个样本对应一个簇。

3.2 初始种子与可复现性

这里值得展开多说几句。K-均值算法有随机性,因为初始种子的选择会影响最终结果。PROC FASTCLUS在默认情况下会从数据中挑选若干“分散且密度大的点”作为种子,而不是完全随机;但为了确保你的分析结果可以被复核,我强烈建议显式指定SEED=。

你可能觉得指定种子只是“图个心里安稳”,但实际项目里,这个习惯能省下大量沟通成本。一次聚类结果分析到一半,某天重跑了一遍代码,结果发现簇编号全变了,整个业务报告推倒重来——这种事我见过不止一次。指定固定种子后,同一数据集、同一参数,跑出来的结果永远一致,报表和结论才能经得起上线审计。

另外要注意的是,SEED本身不影响聚类质量好坏,它只是初始化种子点的方式。如果聚类结果对种子数值特别敏感,说明你的数据本身聚类结构就不清晰,当前K值可能并不合适。后面会在避坑章节里继续聊这个问题。

3.3 OUT=输出集与OUTSTAT=统计集要配合使用

跑完PROC FASTCLUS之后,大多数人只看一眼日志里的频率分布就完事了,其实这样浪费了一半输出。OUTSTAT=生成的统计数据集非常有用,里面包含了每个变量在每个簇内的均值、标准差、整体均值、簇内均方根、整体R方等指标。

这些指标可以用来判断聚类质量:

  • 每个变量的RSquare越高,说明该变量在区分聚类时贡献越大;
  • 变量Cluster Standard Deviation越小,说明簇内越紧凑;
  • 所有变量的整体RSquare一般需要达到0.4以上,聚类成果才有较强的解释力。

举个例子,如果某个变量在簇内的标准差和整体标准差相差无几,说明这个变量对聚类基本没有贡献,可以把它移除后重新建模,看看整体R方是否下降。这个过程,本质上就是一遍又一遍地做“变量敏感性分析”。

3.4 要不要把标准化数据换回原始尺度

聚类结果输出以后,簇中心点和均值都是标准化后的数值,业务方看不懂“收入均值-0.372”是什么意思。所以在最终出报告之前,我会把聚类编号合并回原始宽表,用PROC MEANS按簇统计原始变量的均值、中位数、最大值、最小值,再转成人类可读的画像表。

这个步骤本身不难,但不少人在做完PROC FASTCLUS后直接拿标准化结果去写业务结论,结果解释得一塌糊涂。正确做法是先用CLUSTER变量作为分组字段,对原始数据进行分组汇总。

下面这段代码把原始变量和聚类编号合并在一起,再输出各簇画像:

proc sort data=work.cust_raw out=work.raw_sorted; by cust_id; run; proc sort data=work.cust_cluster out=work.cluster_sorted; by cust_id; run; data work.final_profile; merge work.raw_sorted(in=a) work.cluster_sorted(in=b keep=cust_id cluter); by cust_id; if a and b; run; proc means data=work.final_profile n mean median min max; class cluster; var income spend_freq active_days age; run;

这里的CLUSTER是PROC FASTCLUS生成的簇编号变量,默认名就是CLUSTER。如果你在代码里用了MAXCLUSTERS=5,实际生成几个簇,SAS就会输出几个簇编号。合并时要注意原数据集里有没有cust_id,没有就用行号_N_构造一个临时ID。

4. 选K不靠拍脑袋:肘部图、伪F统计量与业务指标

4.1 为什么“凭经验选K”是个大坑

K-均值聚类最烦人的就是K值选择。很多分析师的“经验法则”是直接拿3或5来试,跑完发现结果好像也说得通,就顺势写进报告。这种做法的最大问题是:你选出来的K未必是数据内在结构的反映,而只是你预设的一个分组数目。换一个K值,得到的画像可能完全不同,而业务方又没有任何依据判断哪个更好。

选K必须结合定量指标,不能只看聚类均值是否“好解释”。好解释是结果反推的,不是说先定K再去解释,而是先有统计证据支持某个K,再去解释这个K下业务上是否合理。

4.2 肘部法则的落地实现

肘部法则的基本思路是看“组内平方和”随K变化的趋势。K越大,组内平方和肯定越小,因为分组越来越细,但到了一定程度后,增加K带来的边际收益会骤降,画成图就像胳膊肘一样拐了个弯,拐弯处对应的K就是相对理想的取值。

在SAS里实现肘部法则,最简单的办法是一次性跑K=2到K=10,并把每个K对应的组内平方和记录下来。这里需要用宏循环:

%macro elbow; %do k = 2 %to 10; proc fastclus data=work.cust_std out=_null_ maxclusters=&k maxiter=50 seed=12345 noprint; var age income spend_freq active_days; run; data _null_; set work.cluster_stats; where _type_ = 'RSQUARE'; call symputx('r2', _value_); run; data _null_; set work.cluster_stats; where _type_ = 'OVERALL'; r2 = symget('r2'); file print; put "K=&k R2=" r2; run; %end; %mend; %elbow;

这个写法比较粗略,但能帮你快速看到不同K下整体R方的变化。更严谨的做法是直接把每个K下的组内平方和输出成一张表,再导入到PROC SGPLOT里画折线图。我一般还会顺带记录每个K下的伪F统计量,这个在PROC FASTCLUS的OUTSTAT里也会输出,后面在PROC CLUSTER的结果里也能看到。

4.3 伪F统计量与CCC指标

SAS里PROC CLUSTER和PROC FASTCLUS输出中,有一个伪F统计量,它衡量的是“簇间方差相对簇内方差的比例”。伪F越大,说明簇间分离度越好。但这个指标有一条大家必须知道的规律:它通常随K值增大而单调增加或先增后减,并不会像教科书里那样给你一个唯一的尖峰。实操中我一般看的是:伪F从某个K开始增速明显放缓,同时整体R方已经达到可接受水平,就选那附近的K。

PROC CLUSTER还会输出一个CCC指标,中文叫立方聚类准则,它在聚类结构呈球形时表现较好,和K-均值的适用前提基本一致。如果你的数据分布比较规整,CCC的峰值所在K值一般就是比较合理的聚类数。

不过说句实在话,统计量只能帮你缩小范围,最终决定K还得看业务解释。比如统计上K=7很好,但业务团队只能理解3类客群,再准确也不能直接用。我之前做过一个耐用品零售项目,统计指标强烈支持分成6类,但和业务方讨论后发现其中两类画像几乎完全重叠,合并成4类反而更利于后续做权益设计。这就说明数据统计与业务规则结合是落地的前提。

4.4 交叉验证式选K:训练集与验证集对比

还有一种适合大样本的选K思路是“交叉验证”。我把样本随机分成训练集和验证集,在训练集上跑PROC FASTCLUS得到簇中心,然后把验证集样本按最近的簇中心分配,再计算验证集上的组内平方和。如果某个K在训练集上表现很好、在验证集上却明显变差,说明这个K存在过拟合。

实际操作中,PROC FASTCLUS把训练集得到的簇中心放到验证集上分配,可以借助PROC SCORE或直接在数据步里写距离计算来实现。哪些场景需要这么严谨?方法论研究、模型上线前的稳定性测试,以及风控领域对分群结果有严格复现要求时。日常探索性分析不一定要做到这个程度,但如果是做大项目,建议不要省。

5. 从聚类编号到可落地的群组画像

5.1 先看簇均值表,别急着讲故事

聚类跑完后,我最反感的就是有人看着簇编号就开始天马行空:“1号簇是时尚白领,2号簇是居家大妈。”这种解读方式的危险在于,它完全绕过了簇均值表,最后根本经不起业务方追问。

正确打开方式是先输出一张各簇均值与整体均值的对比表。大家可以参考下面这种格式:

簇编号样本量占比年龄均值收入均值月消费均值活跃天数均值
1632015.8%45.21280076012.4
21204530.1%31.698003205.8
3842121.1%38.916000112018.6
4882022.0%29.886001803.0
5441011.0%55.3135005208.7

看到这张表之后,我才会结合业务背景去给簇起名。比如簇3的年龄均值适中、收入最高、月消费和活跃天数都明显高,可以初步叫“高活跃品质型用户”;簇2年龄和簇4接近,但收入更高、消费也更高,两者不能混为一谈。

另外要注意,簇均值只是概括,分布不一定都集中。我还会用PROC UNIVARIATE或PROC SGPLOT画每个簇的箱线图,检查是否有簇内出现长尾分布,确保画像不是被少数极端值撑起来的。

5.2 用判别分析验证聚类结果

聚类做完了,怎么证明“这5个簇真的有区别”?一个直接的方法是跑判别分析。用PROC DISCRIM,把聚类编号当作分类变量,把参与聚类的变量当作自变量,看看判别模型能不能高精度地把样本分回各自簇。

proc discrim data=work.final_profile out=work.discrim_out method=normal pool=test crossvalidate; class cluster; var age income spend_freq active_days; run;

如果交叉验证的分类准确率接近100%,说明这5个簇在方差结构上确实分得很开,聚类是真实存在的;如果准确率只有60%,那就说明簇与簇之间边界模糊,K值可能选大了。判别分析在这里不承担“预测”任务,只作为聚类质量的外部验证手段。

还可以顺带看马氏距离。PROC DISCRIM输出中会包含各簇之间的马氏距离平方,距离越大代表两个簇差异越明显。业务上如果你发现某两个簇几乎在所有变量上都不显著,赶紧考虑合并。

5.3 给业务方输出“行动建议”

聚类分析的价值在于后续动作,而不是停在“我们分了5类客户”。每类客户需要不同的权益策略、触达频次、文案调性。这部分我不展开营销文案怎么写,但有个关键点:最后给业务方交付时,我会把每个簇的“标签名、关键统计值、典型特征、建议动作”写成一页纸的画像卡,代码和统计结果放到附录,让业务方只读结论即可。

比如高活跃品质型用户,建议动作可能是“减少打扰频次、赠送高端权益、引导转介绍”;低活跃低价值用户,建议动作可能是“低成本召回、放弃高成本触达”。这些动作描述都基于聚类统计特征,不是凭空想象。这部分内容虽然不算纯技术,但决定了聚类项目能不能真正被业务采纳。

5.4 把聚类编号回填到数据仓库

最后一步是把聚类编号永久性地回填到分析宽表或数据仓库,方便其他模型调用。这里需要注意“聚类编号的时效性”:K-均值聚类的簇中心会随着新数据进入而发生变化,并不是建一次就一劳永逸。在业务场景里,我建议定期重跑聚类,或者用PROC FASTCLUS的种子数据集对存量簇中心做更新。

具体做法是用SEED=指定上一次聚类产生的簇中心数据集,PROC FASTCLUS可以基于已有种子快速分配新样本,而不重新训练。这个技巧在实际工程中非常实用,能避免每个月都因为聚类编号变动导致业务规则失效。

6. K-均值实战避坑指南:种子、重复样本与迭代停滞

6.1 固定种子只是第一步,结果稳定性还要多跑几次

前文我讲过指定SEED=12345可以实现结果可复现,但这不代表你选一次种子就够了。K-均值容易陷入局部最优,不同初始种子可能收敛到不同结果。我自己的操作习惯是:在选定K后,用5到10个不同种子分别跑一次,比较每个种子下生成的簇频率分布和整体R方。

如果不同种子跑出来的簇成员比例差异很大,比如种子A得出的簇1占比20%,种子B得出的簇1占比35%,那就别慌着用其中某一组结果去写报告,而要先回头检查数据里是否存在明显的离群点、K值是否合适、变量是否冗余。一个稳健的聚类结果,不会因为初始种子的变化而格局大乱。

补充一个细节:PROC FASTCLUS里的SEED=控制的是种子选择逻辑,而PROC CLUSTER里也有SEED选项,两者含义不同,不要混用。

6.2 重复样本和恒定性样本会伪装成“一个簇”

前面在数据清洗时提到过重复样本的问题,这里再重点强调一次。如果你对参与聚类的变量做了标准化,而标准化后的数据里存在大量取值完全相同的行,那么PROC FASTCLUS很可能把这一坨“同一坐标”的样本直接当成一个簇,不管它们在业务意义上是否真的应聚在一起。

我去排查过一次诡异聚类:数据量约50万,聚类结果中有一个簇样本量恰好是8000,且这个簇在所有变量上的均值几乎与整体均值一致,标准差接近0。查来查去,根因是多部门上报的同一指标在合并时被重复join了8次,导致8000条完全一样的记录混入数据。

所以我的建议是:在聚类之前,先做一个简单的频数统计,看看是否存在大量重复或近乎重复的行:

proc sort data=work.cust_std out=work.dedup nodupkey; by _all_; run;

对比去重前后的样本量差异,如果差异超过几个百分点,你需要先搞清楚重复的来源,再做聚类。

6.3 迭代不收敛与“少迭代”选项

PROC FASTCLUS是迭代算法,正常情况下几十次迭代足够收敛。如果你的数据非常复杂,或者变量数量特别多,可能会出现迭代到MAXITER上限还没稳定的情况。我在实战里遇到最多的是两类原因:

一是变量量纲差异没有完全消除。虽然做了标准化,但某些变量仍然存在极端偏态,标准化后依然不满足算法对数据分布的假设。二是K值选得过大,导致某些簇里几乎没有样本,中心点在迭代时不断漂移。

遇到迭代不收敛,我不会盲目加大MAXITER,而是先检查是不是有过多的空簇或极小簇。如果K=10时,某个簇样本量只有5个,说明K值显然偏大,迭代结果也没有实际意义,还不如减少K值或者增加“最短距离”限制。

另外PROC FASTCLUS有一个STRICT选项,它控制的是种子分配时是否允许样本被重新分配。默认情况下,算法会在“严格分配”和“可选再分配”之间进行平衡。对于超大数据集,你可以用NOMISS配合STRICT来提高计算效率,但代价是聚类质量可能略降。一般探索阶段不需要动这些高级选项。

6.4 标准化顺序错了,一切白搭

最后这条是我最想提醒的:数据先标准化再聚类,这个顺序不能乱,但很多人在实际项目中会在“过滤样本”之前先做标准化。比如你先把离群点剔除了,再做标准化,和先标准化再剔除离群点,得到的结果完全不同。

原因是标准化的均值和标准差,会受当时样本集合的影响。如果离群点还在集合里,标准化时均值和标准差已经被拉偏了,即使之后你把离群点删了,剩下的样本也已经落在了一个被扭曲的尺度上。正确顺序一定是:先做完整的数据清洗,包括缺失值处理、离群点处理、重复样本排查,再做标准化,最后才进PROC FASTCLUS。

还有一个小坑:PROC STDIZE默认是按变量整体做标准化,如果某个变量有CLASS分组,比如不同地区的客户,你可能需要考虑是否按组标准化。按地区标准化适用于消除地区间的基准差异,但它会抹掉地区间的整体差异,这个选择取决于业务上你是想“看地区内部结构”还是“看全国整体结构”。如果没说清楚,上线后业务方来问“为什么A地区和B地区完全没差异”,你就要一一解释了。

6.5 最后一个小技巧:留一个“无法归属”的簇

做营销分群时,我习惯在正式聚类之外,保留一个“未分类”或“数据不完整”的兜底类别。原因很简单:线上数据永远不干净。总有一部分样本因为缺失值过多、导入异常、格式错误等问题,没法参与聚类或者被聚类结果强行塞进一个并不合适的簇。

我会先用PROC FASTCLUS跑一次正常的聚类,得到一个主模型;然后单独设置一个规则,把那些缺失率超过30%或者离群程度超过阈值的样本标记为“待观察”,不强行分配簇编号。这样业务方在后续营销触达时,可以避免把异常样本当作正常客户来运营,也能在上游数据修复后及时补充分群。

这个做法的副作用是,聚类报告里的样本量可能不等于全量数据,但比起硬生生把所有异常样本都分到一个簇里,这种处理反而更干净,也更尊重数据质量的真实状态。

写到这里,K-均值聚类在SAS里的主要环节基本都过了一遍。从数据清洗、标准化、跑PROC FASTCLUS,再到选K、解读、验证和避坑,每一步都是我实际做项目时反复验证过的路径。不同行业的数据分布差异很大,但底层这套思路是通用的:先看懂变量,再让算法说话,最终用业务逻辑收口。希望这些经验能帮你少走几趟弯路,尤其是那个“先标准化还是先清洗”的顺序,真栽进去过的人才会明白有多痛。

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

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

立即咨询