机器学习基础

k-means 聚类:没有标签怎么分组

14 分钟

前面七节都是监督学习——数据带标签,模型学「输入→答案」的映射。这一节回到无监督学习:只有数据,没有答案,让算法自己找结构。


k-means 的四步循环

目标:把数据分成 个簇。

① 随机选 k 个点作为初始中心
② 把每个样本分给离它最近的中心
③ 重新计算每个簇的中心(取簇内所有点的均值)
④ 回到 ②,直到中心不再移动

就这么简单,而且一定会收敛(每一轮的目标函数都不会增大)。

它在最小化什么:簇内平方和(惯性)

即:让每个点尽量靠近自己簇的中心。


三个必须知道的坑

① 结果依赖初始点

初始中心选得不好,可能收敛到很差的局部最优。

解决:k-means++——初始点不完全随机,而是倾向于选彼此距离远的点。sklearn 默认就用它(init='k-means++'),并且默认跑 10 次取最好的(n_init=10)。

② k 要自己定

算法不会告诉你该分几类。两个常用方法:

肘部法则:把 从 1 到 10 各跑一遍,画「 vs 惯性」曲线。曲线下降由陡变缓的「肘部」就是候选

轮廓系数:衡量「簇内紧密度」和「簇间分离度」,取值 越接近 1 越好。比肘部法则更客观。

from sklearn.metrics import silhouette_score
for k in range(2, 11):
    labels = KMeans(n_clusters=k, n_init=10).fit_predict(X)
    print(k, silhouette_score(X, labels))

③ 只能找「球形」的簇

因为它用欧氏距离、以均值为中心,k-means 假设簇是各向同性的球状且大小相近

遇到这些情况会失败:

  • 月牙形、环形的簇
  • 大小悬殊的簇
  • 密度差异大的簇

替代方案

算法 擅长
DBSCAN 任意形状的簇;自动确定簇数;能识别噪声点
层次聚类 需要树状结构(谱系图);不用预设 k
高斯混合模型 椭圆形簇;给出软分配(属于各簇的概率)

同样必须做特征缩放

和 KNN 一样,k-means 基于欧氏距离,量纲大的特征会主导聚类结果


聚类结果怎么评价

没有标签,就没有「准确率」。 分两种情况:

情况 指标
完全没有标签 轮廓系数、Calinski-Harabasz 指数
有真实标签(用来检验算法) 调整兰德指数 ARI、归一化互信息 NMI

注意不能直接用准确率——聚类给出的簇编号是任意的(把簇 0 和簇 1 换个名字,结果没变但准确率会全错)。ARI 和 NMI 就是为了解决这个问题。


实际用在哪

  • 用户分群:把用户按行为聚成几类,分别做运营策略
  • 图像压缩:把几百万种颜色聚成 16 种,只存簇中心
  • 异常检测:离所有中心都很远的点,可能是异常
  • 特征工程:把「属于哪个簇」当成一个新特征喂给监督模型

最后一条很实用——聚类不一定是终点,它常常是特征工程的一环。

练习:一份数据里,「月消费额」范围是 0–50000,「购买次数」范围是 0–50。不做缩放直接 k-means,聚类结果实际上是按什么分的?

小纸条

k-means 的 k 怎么确定?它假设簇是什么形状,遇到月牙形数据该换什么算法?

登录 后可看答案