R语言实现客户K-means聚类分群与画像问题咨询
R语言K-means客户聚类实操落地解答
先修正你现有代码里的两个显性bug,避免跑不通流程:
- 代码执行顺序错误:你先调用了
km.out$cluster,后面才运行kmeans赋值km.out对象,要把kmeans建模的代码块挪到聚类可视化、聚类结果调用的前面。 - 肘部法则函数传参错误:
wssplot(input, nc = 20)里的input对象未定义,替换为你做过归一化的数据集kpis_scaled即可,即改成wssplot(kpis_scaled, nc = 20)。
问题1:计算各分群未缩放原始值的业务画像指标
聚类输出的标签是和每一行样本一一对应的,不需要对缩放后的聚类中心做反推,直接把聚类标签匹配回原始未缩放的数据集,分组统计即可,反推容易因为归一化参数存储错误出现数值偏差。
建议统计时不要只算均值,把中位数、分群样本量一起算出来,业务侧解读时中位数抗噪性更强,参考价值更高,示例代码如下:
library(dplyr) # 把聚类标签拼接到原始未缩放的数值数据集上 main_kpis_num$cluster <- as.factor(km.out$cluster) # 分组计算各群原始维度的统计值 cluster_raw_profile <- main_kpis_num %>% group_by(cluster) %>% summarise( across( everything(), list( 均值 = ~mean(.x, na.rm = TRUE), 中位数 = ~median(.x, na.rm = TRUE) ) ), 群样本量 = n() )
输出的结果里所有指标都是原始业务量纲,直接可以用来做分群画像解读。
问题2:分布对比高效可视化
(1)归一化前后数值分布对比
不需要逐个变量单独画直方图,把原始值、归一化值合并转成长表,用ggplot分面一次输出所有变量的分布对比即可,注意分面要放开坐标轴尺度,避免量纲差异导致分布形状看不清:
library(tidyr) library(ggplot2) # 合并两类数据转长表 dist_compare_df <- bind_rows( main_kpis_num %>% select(-cluster) %>% mutate(数据类型 = "原始值") %>% pivot_longer(-数据类型, names_to = "指标名", values_to = "数值"), as.data.frame(kpis_scaled) %>% mutate(数据类型 = "归一化值") %>% pivot_longer(-数据类型, names_to = "指标名", values_to = "数值") ) # 分面绘制对比直方图 ggplot(dist_compare_df, aes(x = 数值, fill = 数据类型)) + geom_histogram(alpha = 0.6, bins = 30) + facet_wrap(~指标名, scales = "free", ncol = 3) + theme_bw()
只要两类数据的分布形状完全一致,就说明归一化过程没有出错。
(2)各分群分布与全库平均水平对比
不建议用多系列直方图叠加,辨识度太低,用密度图叠加全库均值参考线即可,一次输出所有维度的组间差异:
# 转长表 cluster_dist_df <- main_kpis_num %>% pivot_longer(-cluster, names_to = "指标名", values_to = "数值") # 计算每个指标的全库均值 global_avg_df <- cluster_dist_df %>% group_by(指标名) %>% summarise(全库均值 = mean(数值, na.rm = TRUE)) # 绘图 ggplot(cluster_dist_df, aes(x = 数值, fill = cluster)) + geom_density(alpha = 0.4) + geom_vline( data = global_avg_df, aes(xintercept = 全库均值), color = "red", linetype = "dashed", linewidth = 1 ) + facet_wrap(~指标名, scales = "free", ncol = 3) + labs(fill = "聚类分群") + theme_bw()
图中红色虚线是全库平均水平,每个分群的密度峰偏离虚线的幅度,就是该群在对应指标上和整体水平的差异。如果需要看离散值分布,把geom_density替换成geom_boxplot即可。
问题3:离群点处理逻辑
K-means基于欧氏距离计算样本相似度,对离群点敏感度极高,必须做离群点处理,但不建议直接删除样本,容易误删核心高价值客户:
- 绝对不要直接套用3σ原则、孤立森林、LOF等通用离群点检测方法删数:客户行为数据是典型的重尾分布,高充值、高活跃的高价值客户本身就处于分布尾端,这类方法会把核心业务群体误判为离群点删掉,直接导致聚类结果失去业务意义。
- 最高效的处理流程分两步:
- 先筛逻辑异常值:对所有指标跑一遍min、max值统计,把不符合业务逻辑的值(比如年龄超过100、充值额为负、活跃天数大于统计周期天数这类采集错误数据)直接剔除,这部分占比通常不到1%。
- 对剩余数据做1%/99%分位的缩尾处理:把小于1%分位的数值替换为1%分位值,大于99%分位的数值替换为99%分位值,不需要删除样本,就能避免极端值拉扯欧氏距离计算结果,跑10万级以上样本速度极快,直接调用
DescTools::Winsorize()函数即可实现。
内容的提问来源于stack exchange,提问作者mamaraci
相关产品推荐
相关产品推荐

