数学原理
本章目标
- 理解 KNN 为什么不通过显式参数优化边界,而是通过邻域关系完成分类。
- 理解闵可夫斯基距离、多数投票、加权投票和
值在当前实现中的数学角色。 - 理解为什么标准化会直接影响 KNN 的预测结果——距离型模型对特征尺度敏感。
重点方法与概念速览
| 名称 | 类型 | 作用 |
|---|---|---|
| 闵可夫斯基距离 | 距离度量 | 当前实现 metric='minkowski' 的底层框架, |
| 多数投票 | 决策规则 | 当前默认 weights='uniform' 对应的预测方式, |
| 加权投票 | 决策规则 | weights='distance' 对应的加权方式,邻居越近权重越大 |
| 超参数 | 决定投票邻域范围,直接控制偏差-方差权衡 | |
| 标准化 | 预处理 | KNN 的距离计算依赖特征尺度,不标准化会导致量纲大的特征主导近邻判断 |
| KD-Tree | 加速结构 | 通过空间划分在低维场景中加速近邻查询, |
1. KNN 的核心思想
KNN(K-Nearest Neighbors)是一种基于实例的懒惰学习算法。它不通过最小化损失函数来学习一组显式参数,而是在预测时直接在训练集中寻找距离最近的
理解重点
- KNN 的核心不是先学一条全局边界,而是"看待预测点周围有哪些样本"。
- 这使 KNN 对局部结构非常敏感,天然能适应非线性边界。
- 同时,这也意味着它对距离定义和数据尺度特别敏感——距离变了,近邻关系就变了。
2. 闵可夫斯基距离:定义"近"的数学框架
闵可夫斯基距离是当前源码 metric='minkowski' 对应的底层框架,通过参数
参数速览
适用参数:metric、p
| 参数名 | 类型 | 说明 | 示例取值 |
|---|---|---|---|
metric | str | 距离度量方式。默认为 "minkowski",是一条通用距离框架:p 控制 | "minkowski"、"euclidean"、"manhattan" |
p | int | 闵可夫斯基距离的幂参数。2 | 1、2 |
闵可夫斯基距离的一般形式:
三种常见特例:
| 名称 | 公式 | 几何直觉 | |
|---|---|---|---|
| 曼哈顿距离 | 只能沿坐标轴移动 | ||
| 欧几里得距离 | 直线距离(默认) | ||
| 切比雪夫距离 | 只考虑最大分量差 |
示例代码
python
from sklearn.neighbors import KNeighborsClassifier
# 默认使用闵可夫斯基距离,p=2(等同欧几里得)
model = KNeighborsClassifier(n_neighbors=5, metric='minkowski', p=2)
# 显式使用曼哈顿距离
model = KNeighborsClassifier(n_neighbors=5, metric='minkowski', p=1)
# 等价写法
model = KNeighborsClassifier(n_neighbors=5, metric='manhattan')理解重点
- 当前源码没有显式设置
p,因此使用默认值(欧几里得距离)。 - 一旦距离定义改变,近邻集合和最终分类结果也会随之变化。
metric='minkowski'是 sklearn 的默认值,它不独立指定距离类型,而是和p参数配合使用。
3. 为什么必须标准化
当不同特征的量纲差异悬殊时,大值特征会主导距离计算(在闵可夫斯基公式中,量纲大的分量对和的贡献更大),因此标准化对 KNN 是必需的:
其中
参数速览
适用类:sklearn.preprocessing.StandardScaler
| 参数名 | 类型 | 说明 | 示例取值 |
|---|---|---|---|
with_mean | bool | 是否中心化(减去均值)。默认为 True | True |
with_std | bool | 是否缩放(除以标准差)。默认为 True | True |
copy | bool | 是否复制输入数据。默认为 True | True |
示例代码
python
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train) # 训练集上拟合统计量并变换
X_test_s = scaler.transform(X_test) # 测试集只变换,用训练集的统计量理解重点
- 对 KNN 来说,标准化不是锦上添花,而是距离型模型几乎必备的预处理。
- 如果不标准化,量纲大的特征会主导
的计算,使得远近关系完全失真。 - 这也是 KNN 与决策树在当前仓库中最关键的工程差异之一——决策树基于阈值切分,不依赖距离尺度。
4. 分类决策规则
多数投票法(当前默认)
对待预测点
加权投票法
考虑距离越近权重越大的方案(weights='distance'):
权重与距离成反比——邻居越近,投票权重越大。
参数速览
适用参数:weights
| 参数名 | 类型 | 说明 | 示例取值 |
|---|---|---|---|
weights | str | 投票权重方式。"uniform" 为等权投票 "distance" 为距离倒数加权 "uniform" | "uniform"、"distance" |
示例代码
python
# 多数投票(当前默认)
model = KNeighborsClassifier(n_neighbors=5, weights='uniform')
# 距离加权投票
model = KNeighborsClassifier(n_neighbors=5, weights='distance')理解重点
- 当前源码默认
weights='uniform',对应多数投票直觉。 - 如果改成
'distance',邻居越近投票影响越大,边界通常更精细,但对噪声也更敏感。 - 这是 KNN 分册里应该重点解释的两个投票策略之一。
5. 值的偏差-方差权衡
| 偏差 | 方差 | 决策行为 | |
|---|---|---|---|
| 小 | 低偏差 | 高方差 | 边界紧密贴合训练样本,对噪声异常敏感,容易过拟合 |
| 大 | 高偏差 | 低方差 | 边界过度平滑,丢失局部结构信息,容易欠拟合 |
参数速览
适用参数:n_neighbors
| 参数名 | 类型 | 说明 | 示例取值 |
|---|---|---|---|
n_neighbors | int | 近邻数量 5 | 1、5、15、50 |
示例代码
python
model = KNeighborsClassifier(n_neighbors=5)理解重点
时每个训练样本自身就是一个 Voronoi 区域中心,训练误差为 0 但泛化差。 是 sklearn 默认值,也是教学上最常见的起点,兼顾了局部性和稳定性。 通常设为奇数以避免二分类平票,但多分类场景中平票仍可能发生。
6. 概率估计
KNN 的概率输出基于邻域内各类别占比:
对于 weights='distance' 的情况,概率为加权占比:
理解重点
- KNN 的概率输出本质上是邻域内的类别频率,这不同于逻辑回归通过 sigmoid 映射得分到概率。
- 由于
较小,概率值只取离散值(如 时概率只能是 ),看起来不如其他模型的概率"平滑"。 - 这些概率是 ROC 曲线的直接输入——需要连续变化的阈值才能画出 TPR/FPR 轨迹。
7. 数学原理如何映射到当前源码
以下表格将本章涉及的数学概念与当前仓库的代码实现一一对应:
| 数学概念 | 数学符号/公式 | 代码实现 |
|---|---|---|
| 闵可夫斯基距离 | metric='minkowski', | |
| 欧几里得距离 | p=2(默认,未显式写出) | |
| 多数投票 | weights='uniform'(默认) | |
| 加权投票 | weights='distance' | |
| 邻域大小 | n_neighbors=5 | |
| 概率估计 | model.predict_proba(X) | |
| 标准化 | StandardScaler().fit_transform(X_train) | |
| KD-Tree 查询 | — | algorithm='auto'(默认,自动选择) |
常见坑
- 把 KNN 当成"会自动学出参数边界"的模型——它是懒惰学习,
fit()只存储数据,不做优化。 - 忽略标准化,让距离关系完全失真——量纲大的特征会主导
。 - 只会机械调
k,却不理解它对应偏差-方差权衡——小低偏差高方差,大 高偏差低方差。 - 把加权投票写成当前默认行为——源码默认
weights='uniform',加权投票需要显式设置。 - 混淆概率估计的来源——KNN 概率来自邻域频率,不是连续函数映射,取值是离散的(分母为
)。
小结
- KNN 的核心数学:用闵可夫斯基距离
定义近邻,再用投票规则 完成分类。 ( n_neighbors)、weights、metric/p和标准化共同决定模型行为——哪一个变了,近邻关系和分类结果都会变。- KNN 不通过最小化损失函数学习参数,
fit()只是存储训练数据,所有计算发生在predict()阶段。