KNN(K Nearest Neighbors)入门笔记
目录
目录
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)——没有训练过程,预测时才临时计算所有样本距离 |
三、距离度量方式
待预测样本向量:
A. 欧氏距离(Euclidean Distance)
KNN 默认距离度量,对应维度差值平方和开平方根。
二维平面点 与 间的距离:
维空间点 与 间的距离:
记忆口诀:对应维度差值的平方和开平方根
B. 曼哈顿距离(Manhattan Distance / City Block Distance)
得名于曼哈顿城市横平竖直的街道布局特点,反映只能沿坐标轴方向移动的限制。
二维平面点 与 间的距离:
维空间点 与 间的距离:
运动规则:只能沿坐标轴方向移动(横平竖直),不能走对角线
记忆口诀:对应维度差值的绝对值求和
C. 切比雪夫距离(Chebyshev Distance)
得名于俄罗斯数学家帕夫努蒂·切比雪夫。在国际象棋中,国王可以直行、横行、斜行,走一步可移动到相邻 8 个方格中的任意一个,国王从一格走到另一格的最少步数即为切比雪夫距离。
二维平面点 与 间的距离:
维空间点 与 间的距离:
运动规则:可以沿坐标轴方向移动,也可以沿对角线方向移动,每一步在任意维度上的最大变化量为 1
记忆口诀:对应维度差值的绝对值,取最大
D. 闵可夫斯基距离(Minkowski Distance)
核心概念:并非一种新的距离度量方式,而是对已有距离公式的概括性总结。
通用公式:
其中 为变参数,且 。
参数特性:
| 参数取值 | 退化的距离名称 | 等价形式 |
|---|---|---|
| 曼哈顿距离 | ||
| 欧氏距离 | ||
| 切比雪夫距离 |
记忆口诀:“p 变我变,1 曼 2 欧无穷切”
四、手工计算欧氏距离示例
1. 美人鱼
2. 功夫熊猫
3. 宝贝当家
五、距离升序排序(由近 → 远)
| 排名 | 电影名称 | 距离 | 类型 |
|---|---|---|---|
| 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值选择核心注意事项
K 过小:模型容易被噪声样本影响 → 过拟合
K 过大:远处不相关样本参与投票,边界模糊 → 欠拟合
实操经验:
优先选择奇数 K(避免票数持平)
通过交叉验证挑选最优 K
额外补充(课堂常考点):
KNN 对特征量纲敏感,数值范围差异大时需要做特征标准化
除欧氏距离,还可使用曼哈顿距离、切比雪夫距离等
七、特征预处理
1. 为什么做归一化和标准化
原因:当特征的单位(量纲)或大小相差较大,或者某特征的方差相比其他特征大出几个数量级时,容易影响(支配)目标结果,使得一些模型无法学习到其他特征。
示例:在判断健康状况的案例中,身高(1.6-1.8m)和体重(60-90kg)的单位差异导致数值范围差异显著,体重特征可能主导模型学习。
影响:量纲差异会导致某些算法(如 KNN)中数值较大的特征权重过高,影响模型对重要特征的识别能力。
2. 归一化(Min-Max Scaling)
1)归一化原理
定义:通过对原始数据进行线性变换,将数据映射到指定区间 (默认 )。
计算公式:
第一步:
第二步:
计算过程示例(数据范围 60-90,目标区间 ):
以数值 90 为例:
以数值 75 为例:
区间调整:可通过修改 和 参数将数据映射到任意区间(如 ),公式具有通用性。
2)归一化特点
| 方面 | 说明 |
|---|---|
| 优点 | 能有效解决特征量纲不一致问题,使各特征权重均衡 |
| 缺点 | 极值敏感:完全依赖最大值和最小值,容易受异常值影响 |
| 适用场景 | 更适合小数据集处理,大数据集建议使用标准化 |
类比说明:如同班级年龄计算,少量异常值(如 90 岁学员)在小样本中影响显著,但在大样本中影响会被稀释。
3)归一化 API
导入方式:
from sklearn.preprocessing import MinMaxScaler
关键参数:
feature_range:缩放目标区间,默认为(0, 1)
主要方法:
| 方法 | 说明 |
|---|---|
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)归一化操作例题
计算要点:
先计算每列的最小值、最大值
按公式分两步计算:
- 先求 (0-1 区间值)
- 再根据目标区间求
注意事项:
测试集必须使用训练集相同的转换规则
分类问题通常只需要对特征列归一化,标签列保持原样
回归问题可能需要同时对特征和标签进行归一化
5)归一化参数 feature_range 详解
| 参数 | 说明 |
|---|---|
| 作用 | 控制输出值的范围,默认为 (0, 1) |
| 自定义设置 | MinMaxScaler(feature_range=(3, 5)) |
| 使用建议 | 区间差值不宜过大(如 3-5 合理,3-500 不合理),否则会失去归一化消除量纲差异的意义 |
6)归一化内容总结
| 要点 | 说明 |
|---|---|
| 核心目的 | 防止因量纲(单位)问题导致特征列方差值相差较大,影响模型最终结果 |
| 映射区间 | 默认将各列值映射到 区间 |
| 计算公式 | 第一步:;第二步: |
| 适用场景 | 容易受最大值和最小值影响,一般用于处理小数据集 |
3. 标准化(Standardization)—— 补充对比
| 对比维度 | 归一化 | 标准化 |
|---|---|---|
| 原理 | 基于最大值和最小值线性缩放 | 基于均值和标准差变换 |
| 公式 | ||
| 输出范围 | 固定区间(如 ) | 无固定范围,均值为 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)