AI 工程地基 29|没有标准答案的机器学习
医院有几百万份病历,没人一份一份地标过病名。电商网站存着几百万个用户会话,没人画过客户分群。安全团队每天盯着海量网络日志,没人逐条标注过哪些是攻击。
到上一课为止,我们写的每个模型都在等一份标准答案。这一课开始,答案没了。
无监督学习处理的就是这种局面:不告诉算法要找什么,让它盯着数据,直到结构自己浮出来。监督学习是拿着答案册学教科书,无监督学习是盯着原始数据发呆,发着发着,看出门道。
代价也明摆着:没有标准答案,就没有准确率可算。你得换一套工具,判断算法找到的结构是不是真有道理。
圆规:K-Means
K-Means 是聚类里的主力,思路简单到可以一句话说完:猜 K 个中心,每个点归给最近的中心,中心挪到自己成员的平均位置,重复到不动为止。
课程给了个四十来行的从零实现。在三个分开的圆数据团上,它第四轮就收敛,质心落在 [5.0, 8.05]、[2.12, 1.98]、[8.11, 3.16]——真实中心是 [5,8]、[2,2]、[8,3],差值都在抽样误差之内。我拿 scikit-learn 的官方版对跑了一遍:惯性 190.2212,两边六个有效数字完全一致。手写实现是过硬的。
惯性这个词值得当场解释一下:每个点到自己质心的平方距离总和,越小说明簇越紧。K 要你自己选,常用的帮手有两个。肘部法:让 K 从 1 涨到 6,惯性跟着掉,掉到某个位置突然变缓,曲线像胳膊肘一样拐弯,那个位置就是合适的 K。轮廓分数:每个点问一句「我离自己人近,还是离隔壁近」,近得多就加分,从 -1 到 +1。这份数据上两个帮手意见一致:肘在 K=3,轮廓分峰值也在 K=3。
一切顺利。顺利,是因为数据是圆的、分得开的、K 是知道的。这三条少一条,下面就有好戏。
月牙翻车现场
课程造了一个故意刁难的数据:两条月牙,上下互扣,每条一百个点,噪声 0.1。然后请两位主角分别上场。
K-Means 的下场课程预告了:会切错。两个质心把月牙各拦腰切断——K-Means 手里只有圆规,两条月牙在它眼里就是该被直线分开的两坨。轮廓分数 0.49,打印的结论是「K-Means splits moons poorly」。
DBSCAN 这一节的标题写着 non-spherical clusters,意思是该轮到它表演处理非球形了——正文说过「DBSCAN 能找任意形状的簇」。
跑出来:Found 1 clusters, 0 noise points。
一簇。两条月牙被焊成了一坨,一个噪声点都没剩。
我用同样的参数喂给 scikit-learn 的 DBSCAN,结果一模一样:1 簇。所以不是手写实现的错,是参数。课程设的邻域半径 eps 是 0.3,而我逐对量了这 200 个点:两条月牙之间最近的一对点,距离 0.169。半径 0.3 的邻域球罩得住这对点,链式反应一路蔓延,两条月牙就连成一体了。
分界线有多窄?我把 eps 从 0.3 往下扫:0.28、0.25、0.22,全是一坨。0.215,焊死。0.210,分开——两簇、零噪声,跟生成数据时的真值对得上 99.5%。分对和焊死之间,窗口宽度不到 0.01,课程选的 0.3 离分界线差了四成。
更扎心的是:生成月牙的函数把真值标签返回了,变量名就叫 moon_labels。主程序从头到尾没碰过它。哪怕拿它对一下答案,1 簇的灾难当场就会暴露。用无监督方法不评估本来情有可原,可真值明明就握在手里。
这就是「不用选 K」的代价。DBSCAN 确实不让你选簇数,但它把决定权挪给了 eps。选 K 选错了,结果是分太粗或者分太细,一眼能看出来;eps 选错了,结果可能像这次一样——整个演示静默失效,不报错,不抗议,打印一行 Found 1 clusters,然后没有一个人发现。
尺子也有立场
翻车之外,还有一层更隐蔽的事。
eps=0.21 的 DBSCAN 把月牙分对了,99.5% 的正确率。它的轮廓分数是多少?0.33。
切错的 K-Means,轮廓分数 0.49。
正确答案的得分,比错误答案低一截。这不是月牙的错,是尺子的。轮廓分数量的是「簇内紧、簇间远」,这套标准天生偏爱紧凑的圆形团。月牙的正确分法,簇内点与点的平均距离天然就大——月牙是拉长的,自己的头离自己的尾巴都远。拿一把偏爱圆的尺子去量非圆形的正确答案,量出来的就是低分。
课程把轮廓分数教成了选 K 的通用工具,没提它这个偏好。在球形数据上它很称职,K=3 的峰值 0.75 指得又准又稳;到了月牙上,它会告诉你错的比对的好。工具没有错,但工具都有立场。用之前得知道它站在哪一边。
软分配和圆盖子
第三位主角 GMM,课程的介绍很动人:K-Means 是硬分配,每个点非此即彼;GMM 是软分配,每个点对每个簇都有一个概率。而且正文原话写着——「GMM 可以建模椭圆形的簇,不像 K-Means 只能球形」。
椭圆是真的,但不在课本写的代码里。
看它的实现:每个高斯的形状参数只有一个方差,一个数。一个方差定形的高斯,等概率线是一组同心圆。想画椭圆,每个方向得有各自的伸展量,那需要一整个协方差矩阵,不是一个数。
我造了个考场验证:两个斜长的椭圆团,一个沿 45 度,一个沿 135 度,长短轴十比一,尾部交叠。用课本的手写 GMM 分:正确率 52%,跟抛硬币差不多。K-Means 反而拿到 68%。换 scikit-learn 的 GMM、打开完整协方差:92%。
有个细节很说明问题:手写版的成绩跟 scikit-learn 强制球形协差的模式一模一样——它实现的本来就是球形 GMM。回到那三个圆团数据上,它和 K-Means 的输出逐点相同,一百五十个点一个不差,轮廓分同为 0.7541。课本术语表里给 GMM 起的通俗名字是「软版 K-Means」,在这份实现里,这个名字名副其实到极致:连能耐都和 K-Means 一样,只会画圆。
椭圆能力不是吹牛,是升级件没装。EM 算法、软分配、概率归属,这些骨架都是真的;把每个高斯手里那个单一的方差数字换成协方差矩阵,椭圆立刻就有。课程把它留成了练习,而正文宣称的能力,得等练习写完才存在。
树和没人要的点
还有两个配角。
层次聚类自底往上盖楼:每个点先自己成一簇,反复合并最近的两个簇,合并的全过程记成一棵树,叫树状图。想要几簇,在树的哪一层剪一刀就行——不用预先选 K,但内存按点数的平方涨。课程讲了四种「远近」的量法(单连接、全连接、平均连接、Ward 法),然后把 Ward 留成了练习,正文实现里没有层次聚类的代码。
异常检测反而是聚类白送的。往三个数据团里扔三个远点 [20,20]、[-5,-5]、[15,0],DBSCAN 的噪声标签全中。GMM 的路子是看每个点在所有高斯下的概率,哪里都低就是怪人。K-Means 的路子是看离最近的质心有多远。练习 3 让你把 DBSCAN 和 GMM 的异常名单对一下——两个方法意见不合的地方,往往就是数据里最有故事的地方。
练习里藏的真话
练习 1 让你实现 K-Means++:第一个质心随机挑,之后每个新质心按「离现有质心的平方距离」加权抽签,越远越可能被选中。我写了,也对比了。六个数据团、360 个点、30 组随机种子:K-Means++ 平均 9.9 轮收敛,随机初始化平均 13.2 轮,快了四分之一。
但解的质量呢?这份数据上,随机初始化的平均惯性 763.9,K-Means++ 反而 783.3;最差情况 915.6 对 1084.6,随机还更稳一些。K-Means++ 的理论保证是期望意义上的——平均不坏,不保证哪一次更好。分离良好的数据上,随便挑质心也能收敛到好解;真正需要它的,是那些初始化一不好就掉坑里的数据。
想亲眼看月牙翻车的话,把课本 DBSCAN 月牙那段的 eps 从 0.3 改成 0.21 再跑一次。Found 1 clusters 变成 Found 2 clusters,零噪声,真值一致率 99.5%。再改成 0.215。一坨和两条月牙之间,隔着 0.005。
讨论回复
加载中...正在加载回复...
智谱 GLM-5 已上线
我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。