Back to Notes

KNN(K Nearest Neighbors)入门笔记

Table of Contents
Table of Contents

KNN算法与距离度量笔记

一、案例分析

数据集

序号 电影名称 搞笑镜头 拥抱镜头 打斗镜头 电影类型
1 功夫熊猫 39 0 31 喜剧片
2 叶问3 3 2 65 动作片
3 伦敦陷落 2 3 55 动作片
4 代理情人 9 38 2 爱情片
5 新步步惊心 8 34 17 爱情片
6 谍影重重 5 2 57 动作片
7 功夫熊猫 39 0 31 喜剧片
8 美人鱼 21 17 5 喜剧片
9 宝贝当家 45 2 9 喜剧片

待预测样本

序号 电影名称 搞笑镜头 拥抱镜头 打斗镜头 电影类型
10 唐人街探案 23 3 17 未知

概念说明

任务

使用 KNN 算法,依据特征预测《唐人街探案》类别。


二、KNN算法原理

KNN(K近邻):将样本视作特征空间中的点,计算未知样本与全部已知样本的相似度(距离),找出距离最近的 K 个邻居,通过多数投票决定未知样本类别。

基础属性

属性 说明
所属范畴 监督学习
适用任务 分类(投票)、回归(均值)
算法类型 惰性学习(Lazy Learning)——没有训练过程,预测时才临时计算所有样本距离

三、距离度量方式

待预测样本向量:X=(23,3,17)X = (23, 3, 17)

A. 欧氏距离(Euclidean Distance)

KNN 默认距离度量,对应维度差值平方和开平方根

二维平面点 a(x1,y1)a(x_1, y_1)b(x2,y2)b(x_2, y_2) 间的距离:

d12=(x1x2)2+(y1y2)2d_{12} = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}

nn 维空间点 a(x11,x12,,x1n)a(x_{11}, x_{12}, \dots, x_{1n})b(x21,x22,,x2n)b(x_{21}, x_{22}, \dots, x_{2n}) 间的距离:

d12=k=1n(x1kx2k)2d_{12} = \sqrt{\sum_{k=1}^{n} (x_{1k} - x_{2k})^2}

记忆口诀:对应维度差值的平方和开平方根


B. 曼哈顿距离(Manhattan Distance / City Block Distance)

得名于曼哈顿城市横平竖直的街道布局特点,反映只能沿坐标轴方向移动的限制。

二维平面点 a(x1,y1)a(x_1, y_1)b(x2,y2)b(x_2, y_2) 间的距离:

d12=x1x2+y1y2d_{12} = |x_1 - x_2| + |y_1 - y_2|

nn 维空间点 a(x11,x12,,x1n)a(x_{11}, x_{12}, \dots, x_{1n})b(x21,x22,,x2n)b(x_{21}, x_{22}, \dots, x_{2n}) 间的距离:

d12=k=1nx1kx2kd_{12} = \sum_{k=1}^{n} |x_{1k} - x_{2k}|

运动规则:只能沿坐标轴方向移动(横平竖直),不能走对角线

记忆口诀:对应维度差值的绝对值求和


C. 切比雪夫距离(Chebyshev Distance)

得名于俄罗斯数学家帕夫努蒂·切比雪夫。在国际象棋中,国王可以直行、横行、斜行,走一步可移动到相邻 8 个方格中的任意一个,国王从一格走到另一格的最少步数即为切比雪夫距离。

二维平面点 a(x1,y1)a(x_1, y_1)b(x2,y2)b(x_2, y_2) 间的距离:

d12=max(x1x2,y1y2)d_{12} = \max(|x_1 - x_2|, |y_1 - y_2|)

nn 维空间点 a(x11,x12,,x1n)a(x_{11}, x_{12}, \dots, x_{1n})b(x21,x22,,x2n)b(x_{21}, x_{22}, \dots, x_{2n}) 间的距离:

d12=maxk=1nx1kx2kd_{12} = \max_{k=1}^{n} |x_{1k} - x_{2k}|

运动规则:可以沿坐标轴方向移动,也可以沿对角线方向移动,每一步在任意维度上的最大变化量为 1

记忆口诀:对应维度差值的绝对值,取最大


D. 闵可夫斯基距离(Minkowski Distance)

核心概念:并非一种新的距离度量方式,而是对已有距离公式的概括性总结

通用公式

d12=k=1nx1kx2kppd_{12} = \sqrt[p]{\sum_{k=1}^{n} |x_{1k} - x_{2k}|^p}

其中 pp 为变参数,且 p1p \geq 1

参数特性

参数取值 退化的距离名称 等价形式
p=1p = 1 曼哈顿距离 k=1nx1kx2k\sum_{k=1}^{n} \vert x_{1k} - x_{2k} \vert
p=2p = 2 欧氏距离 k=1n(x1kx2k)2\sqrt{\sum_{k=1}^{n} (x_{1k} - x_{2k})^2}
pp \to \infty 切比雪夫距离 maxk=1nx1kx2k\max_{k=1}^{n} \vert x_{1k} - x_{2k} \vert

记忆口诀“p 变我变,1 曼 2 欧无穷切”


四、手工计算欧氏距离示例

1. 美人鱼 (21,17,5)(21, 17, 5)

d=(2321)2+(317)2+(175)2=22+(14)2+122=4+196+144=34418.54\begin{aligned} d &= \sqrt{(23-21)^2 + (3-17)^2 + (17-5)^2} \\ &= \sqrt{2^2 + (-14)^2 + 12^2} \\ &= \sqrt{4 + 196 + 144} = \sqrt{344} \approx 18.54 \end{aligned}

2. 功夫熊猫 (39,0,31)(39, 0, 31)

d=(2339)2+(30)2+(1731)2=(16)2+32+(14)2=256+9+196=46121.47\begin{aligned} d &= \sqrt{(23-39)^2 + (3-0)^2 + (17-31)^2} \\ &= \sqrt{(-16)^2 + 3^2 + (-14)^2} \\ &= \sqrt{256 + 9 + 196} = \sqrt{461} \approx 21.47 \end{aligned}

3. 宝贝当家 (45,2,9)(45, 2, 9)

d=(2345)2+(32)2+(179)2=(22)2+12+82=484+1+64=54923.43\begin{aligned} d &= \sqrt{(23-45)^2 + (3-2)^2 + (17-9)^2} \\ &= \sqrt{(-22)^2 + 1^2 + 8^2} \\ &= \sqrt{484 + 1 + 64} = \sqrt{549} \approx 23.43 \end{aligned}

五、距离升序排序(由近 → 远)

排名 电影名称 距离 类型
1 美人鱼 18.54 喜剧片
2 功夫熊猫 21.47 喜剧片
3 宝贝当家 23.43 喜剧片
4 新步步惊心 34.44 爱情片
5 代理情人 40.57 爱情片
6 伦敦陷落 43.42 动作片
7 谍影重重 43.87 动作片
8 叶问3 52.01 动作片

选取 K=5 进行投票

最近 5 个邻居类别:美人鱼(喜剧)、功夫熊猫(喜剧)、宝贝当家(喜剧)、新步步惊心(爱情)、代理情人(爱情)

类型 票数
喜剧片 3
爱情片 2
动作片 0

预测结果:唐人街探案 属于 喜剧片 🎉


六、K值选择核心注意事项

  1. K 过小:模型容易被噪声样本影响 → 过拟合

  2. K 过大:远处不相关样本参与投票,边界模糊 → 欠拟合

  3. 实操经验

    • 优先选择奇数 K(避免票数持平)

    • 通过交叉验证挑选最优 K

  4. 额外补充(课堂常考点)

    • KNN 对特征量纲敏感,数值范围差异大时需要做特征标准化

    • 除欧氏距离,还可使用曼哈顿距离、切比雪夫距离等


七、特征预处理

1. 为什么做归一化和标准化

原因:当特征的单位(量纲)或大小相差较大,或者某特征的方差相比其他特征大出几个数量级时,容易影响(支配)目标结果,使得一些模型无法学习到其他特征。

示例:在判断健康状况的案例中,身高(1.6-1.8m)和体重(60-90kg)的单位差异导致数值范围差异显著,体重特征可能主导模型学习。

影响:量纲差异会导致某些算法(如 KNN)中数值较大的特征权重过高,影响模型对重要特征的识别能力。


2. 归一化(Min-Max Scaling)

1)归一化原理

定义:通过对原始数据进行线性变换,将数据映射到指定区间 [mi,mx][mi, mx](默认 [0,1][0,1])。

计算公式

第一步:

x=xminmaxminx' = \frac{x - \min}{\max - \min}

第二步:

x=x×(mxmi)+mix'' = x' \times (mx - mi) + mi

计算过程示例(数据范围 60-90,目标区间 [0,1][0,1]):

区间调整:可通过修改 mimimxmx 参数将数据映射到任意区间(如 [3,5][3,5]),公式具有通用性。


2)归一化特点

方面 说明
优点 能有效解决特征量纲不一致问题,使各特征权重均衡
缺点 极值敏感:完全依赖最大值和最小值,容易受异常值影响
适用场景 更适合小数据集处理,大数据集建议使用标准化

类比说明:如同班级年龄计算,少量异常值(如 90 岁学员)在小样本中影响显著,但在大样本中影响会被稀释。


3)归一化 API

导入方式

from sklearn.preprocessing import MinMaxScaler

关键参数

主要方法

方法 说明
fit_transform() 首次拟合转换(训练集使用)
transform() 应用已有转换规则(测试集使用)

代码框架

# 3. 准备数据
data = [[90, 2, 10, 40], [60, 4, 15, 45], [75, 3, 13, 46]]

# 4. 初始化归一化对象
transformer = MinMaxScaler(feature_range=(0, 1))

# 5. 对原始特征进行变换
data_transformed = transformer.fit_transform(data)

4)归一化操作例题

计算要点

注意事项


5)归一化参数 feature_range 详解

参数 说明
作用 控制输出值的范围,默认为 (0, 1)
自定义设置 MinMaxScaler(feature_range=(3, 5))
使用建议 区间差值不宜过大(如 3-5 合理,3-500 不合理),否则会失去归一化消除量纲差异的意义

6)归一化内容总结

要点 说明
核心目的 防止因量纲(单位)问题导致特征列方差值相差较大,影响模型最终结果
映射区间 默认将各列值映射到 [0,1][0,1] 区间
计算公式 第一步:x=xminmaxminx' = \dfrac{x - \min}{\max - \min};第二步:x=x×(mxmi)+mix'' = x' \times (mx - mi) + mi
适用场景 容易受最大值和最小值影响,一般用于处理小数据集

3. 标准化(Standardization)—— 补充对比

对比维度 归一化 标准化
原理 基于最大值和最小值线性缩放 基于均值和标准差变换
公式 x=xminmaxminx' = \dfrac{x - \min}{\max - \min} x=xμσx' = \dfrac{x - \mu}{\sigma}
输出范围 固定区间(如 [0,1][0,1] 无固定范围,均值为 0,方差为 1
对异常值敏感度 高度敏感 不敏感(异常值影响被稀释)
适用场景 小数据集、已知边界的数据 大数据集、存在异常值的数据

八、KNN 分类代码实现

8.1 导包

from sklearn.neighbors import KNeighborsClassifier
print("KNeighborsClassifier 导入成功!")

8.2 准备数据集

# 训练特征:9个样本,每个样本3个特征(搞笑、拥抱、打斗)
X_train = [
    [39, 0, 31],   # 功夫熊猫
    [3, 2, 65],    # 叶问3
    [2, 3, 55],    # 伦敦陷落
    [9, 38, 2],    # 代理情人
    [8, 34, 17],   # 新步步惊心
    [5, 2, 57],    # 谍影重重
    [39, 0, 31],   # 功夫熊猫
    [21, 17, 5],   # 美人鱼
    [45, 2, 9]     # 宝贝当家
]

# 训练标签:对应9个样本的分类结果
y_train = ['喜剧片', '动作片', '动作片', '爱情片', '爱情片', '动作片', '喜剧片', '喜剧片', '喜剧片']

# 测试样本:唐人街探案
X_test = [[23, 3, 17]]

8.3 创建分类模型对象

estimator = KNeighborsClassifier(n_neighbors=5)

8.4 模型训练

estimator.fit(X_train, y_train)

8.5 模型预测

y_predicted = estimator.predict(X_test)

8.6 打印预测结果

print(y_predicted)

输出['喜剧片']


九、KNN 回归代码实现

9.1 导包

from sklearn.neighbors import KNeighborsRegressor

9.2 准备数据集

X_train = [[0, 0, 1], [1, 1, 0], [3, 10, 10], [4, 11, 12]]
y_train = [0.1, 0.2, 0.3, 0.4]
X_test = [[3, 11, 10]]

9.3 创建回归模型对象

estimator = KNeighborsRegressor(n_neighbors=3)

9.4 模型训练

estimator.fit(X_train, y_train)

9.5 模型预测

y_predicted = estimator.predict(X_test)

9.6 打印预测结果

print(y_predicted)



0 / 2000
Loading comments...