KMeans:Python聚类算法应用
KMeans 上手实战:用 Python 把用户自动分成几类
做用户运营时,你可能也遇到过这种情况:手里有一堆消费金额、购买频次、最近登录时间的数据,但不知道该把用户分成哪几类。靠人工打标签,费时还容易主观;这时候就可以试试 KMeans 聚类。
KMeans 到底在做什么
KMeans 是一种无监督学习算法,适合没有现成分类标签、想从数据本身发现分组的场景。
它的核心逻辑可以理解成“挑中心、划圈子”:
- 你先指定要分成几类,也就是 k 值;
- 算法随机选 k 个点作为聚类中心;
- 每条数据归到离它最近的中心;
- 再根据每一组的数据重新计算中心;
- 不断重复,直到分组基本不再变化。
这里的“距离”通常用欧氏距离,所以数据量纲差异大时,必须先做标准化。不然消费金额几百上千,购买频次只有几次,金额字段会直接主导聚类结果。
一份可直接套用的 Python 流程
下面用用户消费数据举例,字段可以是最近消费间隔、消费频次、消费金额,也就是常说的 RFM 指标。
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
# 读取数据
data = pd.read_csv("customer_data.csv")
# 选择用于聚类的特征
features = data[["recency", "frequency", "monetary"]]
# 标准化
scaler = StandardScaler()
x = scaler.fit_transform(features)
标准化后,再确定 k 值。很多教程会直接让你设成 3,但实际业务里不能拍脑袋。可以用肘部法观察:
inertia = []
for k in range(2, 9):
model = KMeans(n_clusters=k, random_state=42, n_init=10)
model.fit(x)
inertia.append(model.inertia_)
plt.plot(range(2, 9), inertia, marker="o")
plt.xlabel("聚类数量 k")
plt.ylabel("簇内平方和")
plt.show()
图像下降幅度开始变缓的位置,通常可以作为候选 k 值。不过肘部法只是参考,还要结合业务解释性。分成 6 类后误差可能更小,但如果每一类都说不清用户特征,落地价值也不大。
确定 k 值后训练模型:
kmeans = KMeans(n_clusters=4, random_state=42, n_init=10)
labels = kmeans.fit_predict(x)
data["cluster"] = labels
接着看每一类的特征均值:
summary = data.groupby("cluster")[["recency", "frequency", "monetary"]].mean()
print(summary)
比如你可能得到这样的业务解释:
- 最近消费近、频次高、金额高:重要价值用户;
- 最近消费远、频次低、金额低:流失风险用户;
- 频次高但金额低:高频低价用户;
- 金额高但最近未消费:高价值召回用户。
这样分完群,优惠券、短信召回、会员运营策略才能对应到具体人群,而不是对所有用户发同一套话术。
使用 KMeans 时容易踩的坑
异常值会明显拉偏中心。 KMeans 基于均值计算中心,特别高消费的用户可能让整个簇失真。聚类前可以先做盖帽处理,或者用分位数、对数变换降低极端值影响。
类别型变量不能直接丢进去。 像性别、城市等级这类字段,可以做独热编码;如果类别特别多,要谨慎使用,否则高维稀疏数据会影响距离计算效果。
每次结果可能有差异。 KMeans 初始中心是随机选的,因此代码里建议设置 random_state,并使用较新的 scikit-learn 默认初始化方式。设置 n_init=10 可以让算法跑多次,保留效果最好的一版。
它更适合球形或近似球形的簇。 如果数据分布是环形、极度不规则,或者各类别密度差异很大,KMeans 效果可能不理想,这时可以考虑 DBSCAN、层次聚类等方法。
结尾
KMeans 的优势不在于算法多复杂,而在于简单、速度快、结果容易解释。做用户分层、商品分组、区域聚类时,它往往是一个性价比很高的起点。
真正影响效果的,通常不是模型本身,而是特征有没有选对、数据有没有标准化、k 值是否兼顾指标和业务含义。把这几步处理好,KMeans 就能从一个“算法示例”,变成能辅助运营决策的实用工具。


还没有评论,来说两句吧...