JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

聚类与发现结构

大多数数据到手时并没有标准答案。本文带你认识无监督方法——k 均值、层次聚类与 PCA——在没有人给你标签时,如何从数据中找出分组与结构。

没有标准答案的学习

到目前为止,你在这一级学过的每一种经典方法——回归、决策树、最近邻、支持向量机——都属于 监督学习:每个样本都带着一个 标签,模型学习的是把输入映射到这些已知的答案。但现实世界里的大多数数据并没有标签。你手里有一百万个客户、一堆传感器读数、一个装满文档的文件夹——却没有人告诉你「正确」的分组是什么。这就是 无监督学习 的世界:在没有标准答案时去发现结构。

本章的两件大事是 聚类——把相似的点归到一起——以及 降维——把很多 特征 压缩成少数几个,同时保留要紧的东西。两者都基于同一个想法:数据并不是随机噪声,而是栖身于某种更简单的隐藏形状之上,我们的工作就是把它揭示出来。但有个我们稍后会回头讨论的陷阱:「相似」和「结构」是由你来定义的,而不是数据自己宣告出来的。

k 均值:偏爱圆团的主力工具

k 均值 几乎是每个人学的第一个聚类算法,这是有道理的:它快、简单,而且往往已经够用。你告诉它想要多少个组 k;它撒下 k 个中心,把每个点分配给离它最近的中心,再把每个中心移动到它所辖点的平均位置,如此往复。每一轮都只会让总的平方距离下降,所以它总会稳定下来——通常只需几趟。

  1. 选定 k,撒下 k 个中心,通常取自数据中的随机点。
  2. 分配步:把每个点贴上离它最近的那个中心的标号。
  3. 更新步:把每个中心移动到分配给它的那些点的平均位置。
  4. 重复分配与更新,直到再也没有变动——聚类已经收敛。

这份优雅是有附加条件的。k 均值画的是直线边界,并且暗中假设各个簇都是大小相近的圆团——给它两弯月牙、或者一胖一瘦两个组,它就会切错。它还对中心的初始位置敏感,所以好的实现会跑很多次、保留最好的那次。又因为一切都由距离驱动,你必须先做 特征缩放,否则取值范围最大的那个特征会悄悄地一手遮天。

层次聚类:你数据的家谱

层次聚类 回答的是另一个问题。它不强迫你一开始就选定 k,而是构建一整棵嵌套的分组之树。常见的自底向上版本,先把每个点当作它自己的一个簇,然后反复合并最接近的两个簇,直到所有东西归为一个大簇。这些合并的记录构成一棵叫做谱系图(dendrogram)的树——你可以在任意高度「切一刀」,从而读出你想要的或多或少的簇数。

这棵树本身就是回报:它不仅显示哪些点成组,还显示组如何嵌套进更大的组——物种归入属、属归入科,或者话题归入主题。代价是速度。朴素的实现会在每一步比较每一对簇,其规模大致随点数的立方增长,所以单纯的层次聚类对超大数据集并不实用。你还必须选一个「连接(linkage)」规则——两个簇之间的距离指的是它们最近的两点、最远的两点,还是它们的平均——而这个选择会悄悄地改变答案的形状。

于是有个粗略的经验法则:当你点很多、并且对想要几个组心里有数时,用 k 均值;当数据较小、并且组与组之间的嵌套「关系」本身就是有趣的故事时,用层次聚类。

PCA:找出真正重要的方向

发现结构的另一半是降维。真实的数据集常常有几百个特征,但其中很多是一起变动的——身高与臂展,或者十几道彼此相关的问卷题。主成分分析(PCA)会找出一组新的坐标轴,叫做主成分,并按这样的顺序排列:第一个指向数据散布最开的那个方向,第二个指向次开的方向(且与第一个成直角),依此类推。只保留前面少数几个,你就在几乎不丢东西的前提下压缩了数据。

在底层,PCA 就是你在线性代数那一级见过的 特征向量与特征值,把它们作用在数据的协方差矩阵上:特征向量就是各主成分的方向,每个特征值则告诉你有多少方差沿着它那个方向。这就是全部的诀窍——没有标签,没有训练循环,只有数据如何散布的几何。

# from many features down to 2, for plotting
X = standardize(X)            # center & scale first!
components = top_eigenvectors(cov(X), keep=2)
X2d = X @ components          # each row is now just (x, y)
plot(X2d)                     # eyeball the structure
四行写完 PCA:标准化、取最主要的方向、投影,然后用眼睛看。

PCA 的两大用途是可视化——把高维数据压成二维,让你在跑任何聚类算法之前就能亲眼看见簇——以及对抗 维数灾难,也就是当特征太多时距离会变得没有意义。两点老实话:PCA 只能捕捉 线性 结构,所以它会错过弯曲或扭转的形状,而非线性方法本能抓住它;而且它的成分是你原有特征的混合物,这会让它们难以命名或解释。和 k 均值一样,它也需要 标准化的输入,否则尺度最大的特征会劫持第一主成分。

用好它——以及那些老实的限度

实践中这些工具会串起来用。一个常见的套路是先用 PCA 削掉噪声与维度,再在压缩后的数据上跑 k 均值或层次聚类,最后用一张二维 PCA 图凭肉眼检验结果。聚类还驱动着你大概用过的日常任务:客户分群、按主题给文档归类、压缩图像的颜色,以及 异常检测——那些远离每一个簇的点,就是可疑分子。

现在说说这个领域往往会夸大的硬道理。聚类 永远 会返回一些簇——哪怕在纯随机噪声上也一样。算法对它找到的组是不是真实的毫无概念;它只是去最小化你选定的某个数字。k 的不同取值、距离度量、缩放方式或连接规则的不同选择,会从同一份数据里产出天差地别的「发现」。所以你看到的结构,一部分是数据的属性,一部分是你那些假设的属性,而一个诚实的分析者会把这两者分开来看。

解法不是换一个更好的算法,而是更好的纪律:去验证。同样的分组在一片新的数据上还成立吗?这些簇对领域专家来说有意义吗?换一个随机种子,k 的选择还撑得住吗?把无监督的结果当成有待检验的假设,而不是可以直接上报的事实——这样你就能拿到这些方法真正能给的价值(那可不少),同时不会被那些其实根本不存在的结构骗到。