机器学习基础

KNN:近朱者赤

14 分钟

前面的模型都要「训练」——调参数、算梯度、长树。这一节讲一个几乎不需要训练的算法:K 近邻。


算法只有一句话

要预测一个新样本,就在训练集里找出离它最近的 个样本,看它们大多数属于哪一类。

回归任务就取这 个邻居的平均值。

没有参数要学,没有损失函数要优化。 训练阶段就是把数据存起来——所以它被称为惰性学习(lazy learning)。


三个必须做的决定

① K 取多少

K 效果
K = 1 完全跟着最近邻走,对噪声极敏感,方差高
K 很大 决策边界过于平滑,忽略局部结构,偏差高
K 适中 平衡点,靠交叉验证选

经验起点:,然后用交叉验证微调。二分类时 K 取奇数,避免平票。

② 距离怎么算

距离 公式 适用
欧氏距离 最常用,连续特征
曼哈顿距离 $\sum x_i - y_i
余弦相似度 夹角 文本、推荐(只看方向不看长度)

③ 要不要加权

默认每个邻居一票。更合理的做法是按距离加权——越近的邻居话语权越大(weights='distance')。


最大的坑:必须做特征缩放

这是 KNN 最容易翻车的地方。假设两个特征:

  • 年龄:20–60(跨度 40)
  • 年收入:30000–300000(跨度 270000)

算欧氏距离时,收入的差异会把年龄的差异彻底淹没——年龄差 40 岁贡献 ,收入差 1000 元就贡献 模型实际上只在看收入。

所以用 KNN 之前必须归一化

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

clf = make_pipeline(StandardScaler(), KNeighborsClassifier(n_neighbors=5))

用 Pipeline 包起来很重要:它保证缩放的统计量只从训练集算出,交叉验证时不会泄漏验证集信息。

对比一下:决策树完全不需要这一步(它只看阈值大小)。「要不要缩放」是区分各类模型的一个重要维度。


维度灾难:KNN 的天花板

在高维空间里,「最近」这个概念会失效。

直观理解:维度越高,空间越空旷,所有点之间的距离趋于相等——最近的邻居和最远的点差不了多少,「近朱者赤」的前提就没了。

所以 KNN 适合低维(几维到几十维),高维数据要先降维(下一节的 PCA 就是干这个的)或换模型。


代价:预测慢

训练几乎不花时间,但每预测一个新样本,都要和全部训练数据算距离 个训练样本、 维,单次预测就是

工程上用 KD 树Ball 树加速(sklearn 会自动选),但高维时这些结构也会退化。

一句话总结 KNN 的取舍:把训练的成本推迟到了预测阶段。

练习:一个数据集有「身高(cm)」和「体重(kg)」两个特征,不做归一化直接跑 KNN,模型会主要依据哪个特征判断?为什么?

小纸条

为什么 KNN 必须做特征缩放,而决策树不需要?什么是维度灾难对 KNN 的影响?

登录 后可看答案