首页 / 无监督学习 / 聚类分析

聚类分析:没有标签,怎么把数据分成堆

K-means 的全部内容就是两句话:把每个点分给最近的质心, 把每个质心挪到它那堆的中间。反复做,直到质心不动。 这一页可以一步一步走,看质心怎么挪;也可以切到同心圆, 看它怎么把一个明摆着的结构彻底切错。

聚类结果
inertia 随迭代下降
当前状态

                
              
这一页的 K-means 是自己实现的,labels / 簇中心 / inertia 与 sklearn 逐项对拍过 (给定相同的初始质心后,整个过程是完全确定的)。

① 它在最小化什么

聚类的目标可以写得非常朴素:让每个点到它所属簇中心的距离平方和尽可能小。 这个量叫 inertia(簇内平方和):

右侧那张图画的正是它——每次都只会往下走,不会往上,所以算法一定能停。

② 两步交替 = 坐标下降

  • 分派:固定所有质心,把每个点归给最近的那个。 这一步求的是「给定质心,最优的分派是什么」——每个点独立,直接取最近即可。
  • 更新:固定分派,把每个质心挪到它那一簇的均值位置。 这一步求的是「给定分派,最优的质心在哪」——均值的平方和最小,这是可以严格证明的。

两步都在把 往下压,所以 J 单调不增、算法必然收敛。但注意:每一步都是"固定另一半"的最优, 合起来只能保证停在局部最优——这就是它挑初始质心的根本原因。

③ 为什么它只会切直线

「分给最近的质心」这个规则,在平面上等价于用直线把空间切开 (两个质心连线的垂直平分线)。所以 K-means 的每个簇一定是凸的、大致等大的。

切到「同心圆」看看:内圈和外圈明明是天然的两簇,K-means 却会把外圈劈成两半—— 因为"平分"比"套一个环"更符合它的规则。想聚类这种结构得换方法 (谱聚类、DBSCAN 之类)。

④ 两个必须做的工程处理

  • 标准化特征:inertia 是欧氏距离,量纲差 100 倍时 大的那个特征会完全支配结果。这一页的鸢尾花数据没做标准化, 因为它的两个特征本来就是同一个量纲(厘米)。
  • 跑多次取最优(n_init):算法只保证局部最优, 所以实践中要跑十几次不同起点、取 inertia 最小的那个。 点「换个起点」能看到同一份数据跑出不同的结果。
k-means++ 是干什么的? 随机撒 k 个点当初始质心,很容易撒出两个挨在一起的坏起点。 k-means++ 的做法是:第一个质心随机,之后每个新质心按"到已有质心的距离平方" 成正比的概率来抽——离得越远越容易被选上。于是初始质心天然分散, 这一步几乎不花额外时间,却显著减少"跑出烂结果"的概率。
1. 为什么 K-means 在同心圆上会输得那么难看?
因为它的分派规则是「离哪个质心最近」,而这在平面上等价于用直线切空间。 内外两个圈的正确划分是一条闭合曲线,K-means 的假设空间里根本没有这种形状。 它退而求其次,用两条近似竖直的线把数据砍成三块——看起来"合理", 但和真实结构毫无关系。这不是参数没调好,是模型假设不匹配。
2. 为什么 inertia 一定单调不增?反过来说,这保证了什么、又不保证什么?
分派那一步:给定质心,每个点选最近的,任何别的选法都不会更小—— 所以分派之后 J 不增。更新那一步:给定分派,质心取均值时 J 最小 (把 对 μ 求导等于 0 就得到 μ = 均值)——所以更新之后 J 也不增。 这保证了算法一定会在有限步内停下(J 有下界 0,且取值离散)。 但不保证停在全局最优——只保证是个"没有单步改进余地"的谷底。
3. 页面上点「换个起点」,同一份数据结果就变了。这算 bug 吗?该怎么办?
不算 bug,这是 K-means 的固有性质。办法有三条,实践中通常一起用: ① k-means++ 初始化(比纯随机好很多); ② n_init:跑十几次取 inertia 最小的; ③ 如果数据形状本来就不适合 K-means,换算法。 值得注意的是:inertia 更小不代表聚得更有意义—— 它可以靠把一个自然的簇拆成两半来降低 inertia,但那不是你想看到的结果。
4. k 该怎么选?页面上把 k 从 1 拖到 8,inertia 一直在降,那岂不是越大越好?
inertia 随 k 单调下降(k 越大每个簇越小,当然更"紧"), 极端情况 k = n 时 inertia = 0——但那毫无意义。 常用办法是肘部法则:画 inertia 对 k 的曲线, 找"下降速度突然变缓"的那个拐点。更严谨一点的用轮廓系数 (同时考虑簇内紧密度和簇间分离度)。 但最根本的判据还是业务:分出来的这几堆,有没有实际意义。
5. 鸢尾花那组数据有真实品种标签,页面上的「纯度」是什么意思?
聚类本来没有"正确答案",但如果手头恰好有真实标签(比如鸢尾花的三个品种), 就可以衡量"聚出来的簇和真实分类有多吻合"。 纯度的算法很简单:每个簇认领其中最多的那个真实类别, 正确数加起来除以总数。它不关心簇的编号(簇 0 叫什么无所谓), 所以适合评价无监督结果。
本页在鸢尾花上 k=3 时的纯度是 0.9467——其中 setosa 那一簇 完完全全 50/50 纯(它在花瓣尺寸上和另外两个品种分得很开), 剩下 versicolor 和 virginica 本来就重叠,K-means 只能做到这个程度。 这也说明:纯度是个有用的参照,但它衡量的是"和已知标签吻合多少", 不是"聚类本身好不好"。