想象你是一家书店的店长小陈。凌晨,一批新书送到了店里——整整一千本,没有分类标签,封面五花八门。你的任务是把它们按主题分成几堆,方便明天上架。可是没有标准答案:你不能问“这本书属于文学还是科技”,因为类别根本不存在,全靠你自己从书与书的相似性中发现规律。你大概率会先把书摊开,凭直觉挑几本作为“摊位代表”摆在桌上,然后让其他书各自“投奔”离自己最近的那位代表……过一会儿,你再看看每堆书,把代表换成这堆书里更“居中”的那本……反复几次,每一堆书就自然成型了。这个朴素的过程,就是 K-Means 聚类算法的核心——一次次把样本交给最近的质心,再一次次让质心回归簇的中心,直到一切尘埃落定。本文将沿着这个书店故事,带你完整理解 K-Means 的原理、流程、K 值选择、K-Means++ 初始化、Mini-Batch 加速,以及如何用代码实现它。

岗位关联

K-Means 是无监督学习的基石算法,也是用户画像、图像压缩、异常检测等真实业务中最常用的聚类工具。掌握它的原理与实现,是你迈入数据挖掘与 AI 工程的第一块专业敲门砖。

目录
  1. 可视化演示
  2. 聚类初识:没有标签的书怎么分
  3. K-Means原理:书车与书堆的数学
  4. 算法流程:反复整理的循环
  5. K值选择:分几堆才合适
  6. K-Means++:聪明的初始策略
  7. Mini-Batch K-Means:抽样快速整理
  8. 优缺点分析:书车方法的好与坏
  9. 代码实现:写出整理SOP
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

聚类初识:没有标签的书怎么分

深夜的书店里,小陈望着眼前一千本没有标签的新书发愁。书商只给了他一个模糊的要求:“按主题分堆。”没有标准答案,也没有人告诉他“这本书该放这里”。他能依赖的只有一条朴素的规则:看起来相似的书,应该待在一起。这就是聚类的起点——在没有任何正确答案的情况下,让数据自己说话。

在机器学习里,这样的任务被称为无监督学习。有监督学习像学生对照答案手册做题,而无监督学习像考古学家面对一堆碎陶片,没有说明书,全靠器物之间的相似性推断它们原本属于哪件陶器。聚类就是无监督学习中最典型的家族,它把“相似的对象放进同一组”,不同组之间的差异尽量拉大。

那么,“相似”如何衡量?最自然的办法是计算两个样本之间的距离——距离近,相似度高。对于数值型的样本,常用欧氏距离:

回到书店:小陈判断两本书像不像,本质就是在“封面色调、厚度、标题关键字”等维度上算距离。距离越近的书,被分到同一堆的可能性越大。聚类算法要做的,就是把“以距离找相似”这件事自动化、规模化。当然,距离的度量方式并不唯一,但欧氏距离是 K-Means 的默认选择——它是整套算法的基石。

d(x,y)=∑j=1n(xj−yj)2d(x, y) = \sqrt{\sum_{j=1}^{n}(x_j - y_j)^2}
欧氏距离就是我们在初中几何里学过的“两点之间直线距离”,只不过从二维推广到了 $n$ 维空间。
  1. 维度求和对样本的每个特征维度 $x_j$ 与 $y_j$ 逐项计算差的平方,再全部加起来,$n$ 是特征个数
    ∑j=1n(xj−yj)2\sum_{j=1}^{n}(x_j - y_j)^2
  2. 开根号对平方和取算术平方根,使距离量纲回到原始尺度
    ∑j=1n(xj−yj)2\sqrt{\sum_{j=1}^{n}(x_j - y_j)^2}
  3. 向量差异$x - y$ 在几何上代表两个样本点之间的位移向量,距离就是它的模长
    ∥x−y∥=(x−y)⊤(x−y)\|x - y\| = \sqrt{(x-y)^\top(x-y)}

K-Means原理:书车与书堆的数学

小陈想出了一个办法:他在书店里推来三辆书车,先随便放在三个位置,然后宣布“每本书都去离自己最近的书车那里报到”。书很快分成了三堆。但他发现,有些书离自己的书车其实还挺远——书车摆得不够“居中”。于是他推着每辆书车,走到当前这堆书的“正中间”停下来。这就是 K-Means 的全部直觉:书车是质心,书堆是簇。

质心是什么?它是簇内所有样本点的平均值,数学上记作 $\mu_i$。K-Means 的全部目标,就是找到 $K$ 个质心,使得每个样本点到它所属质心的距离平方和最小。这个目标被称为簇内平方误差和(Sum of Squared Errors,SSE):

小陈发现,SSE 就像“推书的总工作量”:书车放得越居中,每本书要推的距离越短,总工作量越小。K-Means 做的事情,本质上就是不断优化这个“工作量”,直到每辆书车都停在书堆的“重心”上。值得注意的是,这里的 $K$ 是预先给定的——小陈必须先决定“推三辆还是五辆书车”。

SSE=∑i=1K∑x∈Ci∥x−μi∥2\text{SSE} = \sum_{i=1}^{K}\sum_{x \in C_i}\|x - \mu_i\|^2
SSE 衡量所有样本距离自己“书车”的平均远近。SSE 越小,说明每个样本离它所属的簇中心越近,聚类越紧凑。
  1. 外层求和对 $K$ 个簇逐一累加,$i$ 是簇的编号,$C_i$ 表示第 $i$ 个簇内所有样本的集合
    ∑i=1K\sum_{i=1}^{K}
  2. 簇内遍历对第 $i$ 个簇中的每一个样本点 $x$ 求和,理解成“把这堆书的每一本都算一遍”
    ∑x∈Ci\sum_{x \in C_i}
  3. 距离计算$\mu_i$ 是第 $i$ 个簇的质心,$\|x - \mu_i\|$ 表示样本点 $x$ 到质心的欧氏距离
    μi=1∣Ci∣∑x∈Cix\mu_i = \frac{1}{|C_i|}\sum_{x \in C_i}x
  4. 平方放大距离取平方后,偏离质心较远的异常书会受到更大的“惩罚”,推动质心更贴近大多数书
    ∑x∈Ci∥x−μi∥2\sum_{x \in C_i}\|x - \mu_i\|^2

算法流程:反复整理的循环

小陈的整理动作其实只有两步:第一步,把每本书推到离它最近的書车旁边;第二步,推着每辆车走到当前这堆书的平均位置。他不断重复这两步,直到书车几乎不再移动。这个“两步一循环”的过程,就是 K-Means 的完整算法流程。

从数学上讲,分配步骤是最小化每个点到质心的距离——每本书只认离自己最近的车:

分配完成后的下一步是更新:把每辆书车重新推到书堆的“重心”——簇内所有样本的均值:

当所有质心在相邻两轮迭代中位移足够小(小于一个阈值),或者达到预设的最大迭代次数,算法就宣告收敛。小陈发现,他只需重复十来次,书车就不再需要移动了。这个“分配→更新→再分配”的循环单调地降低 SSE,理论上可以证明每次更新都会让 SSE 不增——所以它一定会停下来,只是停在哪里取决于出发位置。

c(x)(t)=arg⁡min⁡i∈{1,…,K}∥x−μi(t)∥2c(x)^{(t)} = \arg\min_{i \in \{1,\dots,K\}}\|x - \mu_i^{(t)}\|^2
更新步骤就是“重新算平均值”:新质心的每个维度,都是簇内样本该维度的均值。
  1. 簇的大小$|C_i^{(t)}|$ 是第 $t$ 轮第 $i$ 个簇的样本总数,作为分母做归一化
    ∣Ci(t)∣|C_i^{(t)}|
  2. 求和$\sum_{x \in C_i^{(t)}} x$ 把簇内所有样本向量逐维度相加,得到“总位置向量”
    ∑x∈Ci(t)x\sum_{x \in C_i^{(t)}} x
  3. 取平均总位置向量除以样本数,得到新的质心 $\mu_i^{(t+1)}$
    μi(t+1)=1∣Ci(t)∣∑x∈Ci(t)x\mu_i^{(t+1)} = \frac{1}{|C_i^{(t)}|}\sum_{x \in C_i^{(t)}} x

K值选择:分几堆才合适

第二天,隔壁书店的老板跑来问小陈:“你怎么知道要分三堆,而不是两堆或五堆?”小陈一愣,意识到 $K$ 是算法不会替你做决定的问题。K 值选择是 K-Means 使用中最关键的“人工环节”——选少了,不同主题的书混在一起;选多了,同一主题的书被拆得七零八落。

最直观的工具是肘部法则:把不同 $K$ 值对应的 SSE 画成折线图,随着 $K$ 增大,SSE 不断下降,但下降速度会在某个点之后明显放缓——这个拐点就像人的手肘,就是推荐的 $K$。另一个常用指标是轮廓系数,它同时评估“簇内紧密”和“簇间分离”:

不过,小陈最终选了 $K=3$,理由很简单——书架只有三个区域,这是业务约束。算法指标只是建议,K 的最终取值永远要回归业务场景:客户分群要“运营团队能分别设计策略”,图像压缩要考虑“颜色种类太多会不会增大文件体积”。肘部法则给出统计上的拐点,轮廓系数给出质量评分,但拍板的永远是业务需求。

s(i)=b(i)−a(i)max⁡{a(i),b(i)}s(i) = \frac{b(i) - a(i)}{\max\{a(i), b(i)\}}
轮廓系数 $s(i)$ 的取值范围是 $[-1,1]$。越接近 1,说明样本 $i$ 离自己的簇内伙伴近、离其他簇远,聚类效果越好。
  1. 簇内距离$a(i)$ 是样本 $i$ 到同簇其他样本的平均距离,越小说明簇内越紧密
    a(i)=1∣Ci∣−1∑j∈Ci,j≠i∥xi−xj∥a(i) = \frac{1}{|C_i| - 1}\sum_{j \in C_i, j \neq i}\|x_i - x_j\|
  2. 最近邻簇距离$b(i)$ 是样本 $i$ 到最近的其他簇中所有样本的平均距离,越大说明簇间分离越彻底
    b(i)=min⁡k≠i1∣Ck∣∑j∈Ck∥xi−xj∥b(i) = \min_{k \neq i}\frac{1}{|C_k|}\sum_{j \in C_k}\|x_i - x_j\|
  3. 归一化比值$b(i)$ 减去 $a(i)$ 后除以两者中的较大值,把结果压缩到 $[-1, 1]$ 区间
    b(i)−a(i)max⁡{a(i),b(i)}\frac{b(i) - a(i)}{\max\{a(i), b(i)\}}

K-Means++:聪明的初始策略

小陈最开始随便放了三辆书车,结果第一轮几乎所有的书都挤向离门口最近的那辆车,另外两辆车空空如也。他折腾了好几次,才把书车的位置“调教”好。这暴露了 K-Means 的一大弱点:对初始质心敏感——初始放不好,最终结果可能被困在一个不太理想的局部最优里。

一位老员工传授了小陈一个诀窍:第一辆书车随便放,之后每放一辆新车时,尽量远离已经放好的书车。具体做法是:先随机选第一个质心;然后计算每个样本点到最近质心的距离 $D(x)$,按 $D(x)^2$ 的概率采样第二个质心;重复直到选出 $K$ 个。这就是大名鼎鼎的 K-Means++ 初始化策略:

小陈照做之后惊喜地发现,三轮之内书车就稳稳地停在了三堆书的中心,几乎不需要额外“返工”。K-Means++ 不是改变了迭代逻辑,而是给教科书式的 K-Means 装上了聪明的“起跑姿势”。这也是为什么今天 sklearn 的 KMeans 默认 init='k-means++',而不是纯随机初始化——花很小的代价,就换来了显著更稳定的聚类结果。

P(x)=D(x)2∑x′∈XD(x′)2P(x) = \frac{D(x)^2}{\sum_{x' \in X}D(x')^2}
$P(x)$ 是样本 $x$ 被选为下一个初始质心的概率。距离已有质心越远的样本,越有资格当“新书车”。
  1. 最近距离$D(x)$ 表示样本点 $x$ 到所有已选质心的最近距离
    D(x)=min⁡j∥x−μj∥D(x) = \min_{j}\|x - \mu_j\|
  2. 距离平方对 $D(x)$ 取平方,让远距离样本的概率优势进一步放大,避免新质心扎堆
    D(x)2D(x)^2
  3. 归一化除以所有样本 $D(x')^2$ 的总和,把权重转换为概率分布,保证所有点被选中的概率之和等于 1
    D(x)2∑x′∈XD(x′)2\frac{D(x)^2}{\sum_{x' \in X}D(x')^2}

Mini-Batch K-Means:抽样快速整理

书店的规模越开越大,从一千本书变成了一百万本。小陈发现,每次迭代都要把一百万本书全部检查一遍,实在太慢。他灵机一动:每次只随机抽出其中的一小摞书,比如三十本,根据这三十本的位置微调书车。虽然每轮信息不完整,但很多轮下来,书车依然能准确停在正确的位置——这就是 Mini-Batch K-Means 的思想。

小批量版本的更新规则与经典 K-Means 不同,它引入了类似“学习率”的机制,让质心向小批量样本的均值方向平滑移动:

小陈发现,用 Mini-Batch 策略后,整理一百万本书只需要原来十分之一的时间,书车最终停靠的位置与全量计算几乎一致。当然,代价是精度上的轻微损失——小批量采样引入了随机噪声,SSE 可能比全量版本略高。但在海量数据的真实业务中,“很快得到一个足够好的结果”远比“很慢地得到一个完美结果”更有价值。

μi←μi+η(x−μi)\mu_i \leftarrow \mu_i + \eta(x - \mu_i)
其中 $\eta$ 是学习率(通常随迭代轮数递减),$x$ 是当前小批量中属于簇 $i$ 的样本。这个公式让质心“挪一小步”,而不是被一批样本直接拉走。
  1. 残差方向$x - \mu_i$ 是样本 $x$ 相对于质心 $\mu_i$ 的偏移向量,指向样本所在方向
    x−μix - \mu_i
  2. 学习率缩放$\eta$ 决定质心向样本移动的比例,取值在 $(0,1)$ 之间,控制每次更新的步长
    η(x−μi)\eta(x - \mu_i)
  3. 移动更新质心在原来位置上叠加一小步偏移,形成新的质心位置
    μi←μi+η(x−μi)\mu_i \leftarrow \mu_i + \eta(x - \mu_i)

优缺点分析:书车方法的好与坏

小陈的“书车整理法”优点显而易见:简单、直观、快。他不需要任何人工标注,只要设定书车数量,机器就能自动把书整理好。这是 K-Means 能成为最流行聚类算法的重要原因——算法简洁,时间复杂度为 $O(n \cdot K \cdot T)$,其中 $n$ 是样本数,$K$ 是簇数,$T$ 是迭代轮数,三者通常都在可控范围内,百万级数据也能轻松处理。

但书车方法也有明显的“性格缺陷”。第一,它必须预先知道要分几堆($K$ 值);第二,初始书车放不好,可能钻进局部最优;第三,它用均值定义“中心”——如果有一本奇厚无比的大字典混在小说堆里,书车会被它硬生生拉偏,这就是离群点敏感;第四,它对簇的形状有隐性假设,倾向于找出紧凑的球形簇,面对月牙形或环形分布的数据会力不从心。理解这些优缺点,你才知道什么时候该用它,什么时候该换成 DBSCAN 或层次聚类。

O(n×K×T)O(n \times K \times T)
这个复杂度说明 K-Means 的运行代价与样本量、簇数、迭代次数都成正比,三者都不能无节制增长。
  1. 样本量 $n$每一轮迭代都要遍历全部样本,这是不可避免的基础开销
    nn
  2. 簇数 $K$每个样本都要与 $K$ 个质心计算距离,簇数越多,每轮耗时越长
    n×Kn \times K
  3. 迭代次数 $T$整个分配-更新循环重复 $T$ 轮,$T$ 通常由收敛条件决定
    n×K×Tn \times K \times T

代码实现:写出整理SOP

小陈的整理法最终被写成了厚厚的《书店自动整理操作手册》(SOP)。新来的店员只需要照着手册执行,就能在几分钟内完成原本需要一整夜的工作。在编程世界里,这份 SOP 就是 K-Means 的代码实现——你既可以手写核心逻辑,也可以直接调用成熟库。

Python 的科学计算生态让手写 K-Means 变得异常简洁。使用 sklearn 更是只需一行:

如果你希望深入理解算法内核,手写版本同样很有价值。手写代码的核心逻辑包括三个部分:初始化质心、分配样本、更新质心。当相邻两轮质心位移小于阈值时,迭代停止。整个过程遵循着同一个不变量——每一轮更新都保证 SSE 不会上升:

小陈把 SOP 交给新店员的那一刻,书店的整理工作完成了从“人工经验”到“自动化流程”的跃迁。K-Means 的代码实现同样如此——短短几十行,就能让电脑代替人眼完成大规模聚类的判断。从原理到代码,你会发现复杂的机器学习算法,其核心往往就是几个反复执行的基本操作。

SSE(t+1)≤SSE(t)\text{SSE}^{(t+1)} \le \text{SSE}^{(t)}
这个不等式是 K-Means 收敛性的理论保障:质心按均值更新后,每个簇的内聚程度只会更好,不会更差。
  1. 第 $t$ 轮误差$\text{SSE}^{(t)}$ 表示第 $t$ 轮迭代后的簇内平方误差和
    SSE(t)\text{SSE}^{(t)}
  2. 下一轮误差$\text{SSE}^{(t+1)}$ 是更新质心并重新分配后的误差
    SSE(t+1)\text{SSE}^{(t+1)}
  3. 单调不增$\le$ 表示更新后的误差不会大于更新前,这是 K-Means 保证收敛的数学基础
    SSE(t+1)≤SSE(t)\text{SSE}^{(t+1)} \le \text{SSE}^{(t)}
python4 行
from sklearn.cluster import KMeansmodel = KMeans(n_clusters=3, init='k-means++', max_iter=300, n_init=10)model.fit(X)labels = model.predict(X)

AI 应用场景

电商客户分群

阶段:数据预处理与特征工程

解决的问题:传统做法是按“消费金额高低”把客户简单分为大客户和小客户,但忽略了消费频率、品类偏好、活跃时段等多维特征,分群粗糙,运营策略难以精准。K-Means 能基于多个特征自动发现客户的内在结构,让运营团队针对不同簇设计差异化策略。

具体案例:某电商平台抽取用户的月均消费额、购买频次、客单价、最近一次购买距今天数四个特征做标准化后,用 K-Means($K=4$)聚类得到“价格敏感型”“高频低消型”“高价值忠诚型”“沉睡唤醒型”四类人群。运营针对每一类推送不同的优惠券模板,转化率提升了 23%。

图像颜色量化与压缩

阶段:图像预处理

解决的问题:一张彩色图片往往包含数万种颜色,存储和传输开销很大。传统做法是直接压缩像素数据,但效果有限。K-Means 可以把所有像素的 RGB 颜色聚成有限的 $K$ 种代表色,用代表色索引替代原始颜色值,大幅降低图像体积。

具体案例:某在线教育平台需要将教学课件中的插图压缩到原体积的 20%。工程师对每个像素的 RGB 向量做 K-Means 聚类($K=16$),用 16 种代表色重建图像。肉眼几乎看不出画质损失,图片体积却缩小到原来的约六分之一。

异常行为检测

阶段:模型部署与监控

解决的问题:正常的系统操作行为高度相似,而攻击行为往往“形迹可疑”。传统规则匹配容易漏报新型攻击。利用 K-Means 对正常行为做聚类,凡是离所有质心都很远(比如距离超过某个分位数)的样本,就被判定为异常。

具体案例:某银行的风控系统对每笔交易的金额、时间、设备指纹、IP 地理位置等特征做 K-Means 聚类,$K=5$ 个簇代表五种常见交易习惯。一笔在深夜从异地新设备发起的超大额转账,在聚类结果中距离最近的质心仍有 3.2 个标准差,被自动标记为高风险并触发二次验证,成功拦截了一起电信诈骗。

Python 演示

python44 行
import numpy as np def make_data(n=300, k=3, seed=42):    rng = np.random.default_rng(seed)    centers = rng.uniform(-10, 10, size=(k, 2))    X = np.vstack([rng.normal(c, 1.5, size=(n // k, 2)) for c in centers])    return X class KMeans:    def __init__(self, k=3, max_iter=100, tol=1e-4):        self.k = k        self.max_iter = max_iter        self.tol = tol        self.centers_ = None     def fit(self, X):        rng = np.random.default_rng(0)        idx = rng.choice(len(X), self.k, replace=False)        self.centers_ = X[idx].astype(float)        for _ in range(self.max_iter):            labels = self._assign(X)            new_centers = np.array([X[labels == i].mean(axis=0) for i in range(self.k)])            shift = np.linalg.norm(new_centers - self.centers_)            self.centers_ = new_centers            if shift < self.tol:                break        return self     def _assign(self, X):        diff = X[:, None, :] - self.centers_[None, :, :]        dist2 = np.sum(diff * diff, axis=2)        return np.argmin(dist2, axis=1)     def predict(self, X):        return self._assign(X) if __name__ == "__main__":    X = make_data()    model = KMeans(k=3)    model.fit(X)    pred = model.predict(X)    for i in range(model.k):        print("簇 %d 样本数: %d" % (i, np.sum(pred == i)))    print("质心:\n", model.centers_)
目的:用 NumPy 从零实现一个可运行的 K-Means 聚类算法,在生成的合成数据上演示“初始化—分配—更新—收敛”的完整流程。
  1. idx = rng.choice(len(X), self.k, replace=False)随机无放回抽取 $K$ 个样本作为初始质心,对应书车最初的随机摆放。
  2. diff = X[:, None, :] - self.centers_[None, :, :]利用 NumPy 广播机制,让每个样本与每个质心两两相减,得到三维差向量数组。
  3. dist2 = np.sum(diff * diff, axis=2)对特征维度求平方和,得到逐样本到逐质心的距离矩阵。
  4. np.argmin(dist2, axis=1)对每个样本取距离最小的质心索引,完成“每本书投奔最近书车”的分配步骤。
  5. new_centers = np.array([X[labels == i].mean(axis=0) for i in range(self.k)])把每个簇内的样本取均值,更新质心位置。
  6. if shift < self.tol: break当质心总位移小于阈值时提前退出循环,对应“书车不再需要移动”的收敛判断。

常见误区

误区“我把 K 设得很大,每个簇都特别紧凑,SSE 嗖嗖往下降,聚类一定更准、更有用!”

正解SSE 随着 K 增大几乎必然是单调下降的——你把每本书都单独放一摞,SSE 当然是零,但这样的“聚类”没有任何意义。K 过大会把原本自然的主题拆成碎片,簇失去可解释性。正确的做法是综合肘部法则、轮廓系数和业务需求选一个“够用且可解释”的 K,而不是盲目追求低误差。

为何常见:人们习惯用“误差越低越好”来评判模型,但聚类没有标签,低误差并不能反映簇的语义价值。

误区“把数据丢给 K-Means,它应该能自动判断我的数据该分成几类吧?”

正解K-Means 有一个必须由使用者预先提供的参数 $K$,算法本身不会也无法自动判断簇数。选 K 是在算法运行之前的人工决策环节,K-Means 只负责在给定 K 的前提下把数据分好。库函数的默认值(如 sklearn 的 n_clusters=8)并不意味着 8 就是正确答案。

为何常见:许多封装好的聚类接口看起来“开箱即用”,新手容易把参数默认值误认为算法自动选择的结果。

误区“用户年龄和年收入直接放进 K-Means 算距离就行,单位不同有什么关系?”

正解欧氏距离对量纲非常敏感。年收入以“元”为单位时数值可能是几万,年龄只有几十,收入会完全主导距离计算结果,导致聚类结构被单一特征绑架。正确做法是先做标准化(如 z-score 或 min-max 归一化),让每个特征处在相近的尺度上再聚类。

为何常见:日常比较数字大小时,我们很自然地忽略单位差异,但在向量空间中不同特征之间的“距离贡献”会被量纲直接放大。

误区“K-Means 迭代几百轮总会收敛到同一个结果,初始质心选什么都一样。”

正解K-Means 保证收敛到某个局部最优解,但不同初始质心可能收敛到完全不同的局部最优。比如三辆书车初始都放在书店门口,最终结果和分散放置会有显著差异。K-Means++ 初始化或多次随机初始化(n_init=10)取 SSE 最低的一次,能显著提升稳定性。

为何常见:“收敛”本身带有“找到正确答案”的暗示,但局部收敛和全局最优是两回事,初学者容易混淆。

误区“K-Means 这么通用,月牙形、环形、长条形的数据它应该都能聚好吧?”

正解K-Means 基于欧氏距离和均值更新,天然偏好紧凑的球形簇。对于月牙形(two moons)或同心圆环(concentric circles)数据,K-Means 会把本属于同一簇的连续区域硬生生切成两半。这类场景应改用 DBSCAN 等密度聚类算法。

为何常见:教科书上的示例数据几乎都是“三团毛线球”,让人误以为真实数据天然呈现球形分布。

面试题

Q1. K-Means 属于哪种机器学习范式?

单选题 · easy

  • A.强化学习算法
  • B.有监督分类算法
  • C.无监督聚类算法← 正确答案
  • D.半监督回归算法

答案:C。K-Means 处理的是没有标签的数据,目标是自动发现数据的内在分组结构,因此属于无监督学习。强化学习强调与环境交互获得奖励,有监督分类需要标签,回归预测连续值,都不符合。

Q2. K-Means 优化目标函数是什么?

单选题 · mid

  • A.最小化簇内平方误差和← 正确答案
  • B.最大化簇间样本距离
  • C.最小化所需质心数量
  • D.最大化数据总体方差

答案:A。K-Means 的目标是让每个样本离自己所属质心的距离平方和(SSE)最小,对应“书车尽量靠近书堆中心”。最大化簇间距离是某些其他聚类的思路,质心数量由 K 决定而非目标函数,C、D 均不符合算法定义。

Q3. K-Means 的“分配步骤”执行什么操作?

单选题 · mid

  • A.将样本分配到最近质心← 正确答案
  • B.更新质心为簇内均值
  • C.随机打乱全体样本顺序
  • D.计算所有样本的方差

答案:A。分配步骤对每个样本计算它与所有质心的距离,并把它归入最近质心的簇,就像每本书去找离自己最近的书车。更新质心是“更新步骤”而非分配步骤,随机打乱和计算方差都不是 K-Means 的操作。

Q4. K-Means++ 主要解决什么问题?

单选题 · mid

  • A.改善初始质心敏感性← 正确答案
  • B.加速每次迭代速度
  • C.自动确定聚类的 K 值
  • D.减少需要的簇数量

答案:A。K-Means++ 通过“选择离已有质心更远的点”的概率采样策略,让初始质心分布更分散,从而减少陷入局部最优的风险。它不改变迭代步骤,也不自动选 K,更不减少簇数——它只改善初始质心的质量。

Q5. 肘部法则主要用于什么?

单选题 · easy

  • A.通过拐点辅助选择 K← 正确答案
  • B.初始化质心的策略
  • C.加速收敛的优化手段
  • D.对数据做标准化处理

答案:A。肘部法则绘制不同 K 值下 SSE 的曲线,寻找 SSE 下降速度明显放缓的“拐点”作为推荐 K。它不负责初始化、不加速迭代、也不做数据预处理,只是选 K 的启发式工具。

Q6. Mini-Batch K-Means 的主要优点是什么?

单选题 · mid

  • A.训练速度大幅提升← 正确答案
  • B.聚类精度必然更高
  • C.自动确定簇的数量
  • D.不再需要初始化质心

答案:A。Mini-Batch K-Means 每轮只用一小批样本更新质心,计算量显著减少,训练速度大幅提升。代价是精度可能略有损失,绝非必然更高;它没有自动选 K 的能力,也依然需要初始化质心。

Q7. 以下哪个因素对 K-Means 结果的影响最深远?

单选题 · hard

  • A.样本特征的数量多少
  • B.数据是否附带了标签
  • C.初始质心的选择好坏← 正确答案
  • D.迭代次数的上限值

答案:C。K-Means 对初始质心非常敏感,不同的初始位置可能收敛到不同的局部最优,直接决定最终聚类结构。特征数量多可以通过降维缓解,数据本身无标签是前提,迭代次数只要设得足够大通常不是瓶颈。

Q8. 下列哪些是 K-Means 的缺点?

多选题 · mid

  • A.需要预先设定 K 值← 正确答案
  • B.初始质心选择敏感← 正确答案
  • C.可以自动确定簇数
  • D.对离群点异常敏感← 正确答案

答案:ABD。K-Means 必须在运行前指定簇数 K;初始质心不同可能导致结果差异很大;质心用均值计算,离群点会把质心显著拉偏,因此对离群点敏感。C 恰恰相反,K-Means 完全不能自动确定簇数。

Q9. 哪些措施可以有效改善 K-Means 的聚类结果?

多选题 · hard

  • A.采用 K-Means++ 初始化← 正确答案
  • B.多次随机初始化取最优← 正确答案
  • C.聚类前先标准化特征← 正确答案
  • D.减少迭代次数上限

答案:ABC。K-Means++ 让初始质心更分散,多次随机初始化可以从多个起点中挑选 SSE 最低者,标准化特征能避免量纲对距离的扭曲,这三者都能改善结果。减少迭代次数反而可能导致算法未收敛就提前停止。

Q10. 关于轮廓系数的说法,哪些是正确的?

多选题 · mid

  • A.取值区间是 [-1, 1]← 正确答案
  • B.值越大聚类效果越好← 正确答案
  • C.可用于辅助选择 K 值← 正确答案
  • D.必须人工逐点计算

答案:ABC。轮廓系数由簇内距离 a 和最近邻簇距离 b 的比值定义,范围在 -1 到 1 之间,越接近 1 表示样本与自身簇紧密、与其他簇分离,聚类效果越好。通过比较不同 K 值的平均轮廓系数可以辅助选 K。实际计算由算法批量完成,不需要人工逐点计算,D 错误。