You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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等通用离群点检测方法删数:客户行为数据是典型的重尾分布,高充值、高活跃的高价值客户本身就处于分布尾端,这类方法会把核心业务群体误判为离群点删掉,直接导致聚类结果失去业务意义。
  • 最高效的处理流程分两步:
    1. 先筛逻辑异常值:对所有指标跑一遍min、max值统计,把不符合业务逻辑的值(比如年龄超过100、充值额为负、活跃天数大于统计周期天数这类采集错误数据)直接剔除,这部分占比通常不到1%。
    2. 对剩余数据做1%/99%分位的缩尾处理:把小于1%分位的数值替换为1%分位值,大于99%分位的数值替换为99%分位值,不需要删除样本,就能避免极端值拉扯欧氏距离计算结果,跑10万级以上样本速度极快,直接调用DescTools::Winsorize()函数即可实现。

内容的提问来源于stack exchange,提问作者mamaraci

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 08:09:21