K 近邻算法 (KNN)
导语:机器学习两套合理分类体系
机器学习有两套主流划分维度,不要混在一起讲:
- 按学习方式(有无标签)划分:有监督学习、无监督学习、半监督学习、强化学习
- 按任务输出划分:分类任务、回归任务、聚类任务
很多初学者容易混淆两套分类,KNN 属于有监督学习 ,它既可以完成分类任务 ,也可以完成回归任务。
一、按学习方式划分(训练数据是否带标签)
1. 有监督学习
训练集同时具备:输入特征 X + 标签 Y(已知正确答案)。模型学习特征到标签的映射关系。
- 子任务:
- 分类:输出离散类别标签
- 📌例子:根据花瓣长宽,判断这朵花是玫瑰、百合还是郁金香;根据邮件内容,判断是否为垃圾邮件。
- 回归:输出连续数值
- 📌例子:根据房屋面积、楼层、地段,预测房子的成交价格;根据历史天气数据,预测明天的温度。
- 分类:输出离散类别标签
- 代表算法:KNN、逻辑回归、决策树、线性回归、随机森林
2. 无监督学习
训练集只有特征 X,没有标签 Y,算法自主挖掘数据内部结构,没有人给标准答案。
- 子任务:聚类、降维、异常检测、关联规则
- 📌例子:电商平台对用户购物行为做分组,自动划分出 "学生党""高消费人群""性价比用户",事先并不知道有哪几类人;对一堆图片自动把相似图片归为一组。
- 代表算法:K‑Means、PCA 主成分分析
3. 半监督学习
少量样本带有标签,大量样本无标签。利用少量标注 + 海量无标注样本共同训练。
- 📌例子:做图片识别,只有 100 张图片人工标注了 "猫 / 狗",硬盘里还有 10000 张没有打标签的猫狗图片,算法同时使用这两部分数据训练模型。
- 适用场景:打标签成本极高,工业标注数据集经常遇到。
4. 强化学习
没有固定数据集。智能体 Agent 和环境交互,执行动作,接收奖励 / 惩罚信号,迭代优化行动策略。
- 📌例子:训练游戏 AI 玩游戏,AI 不断操作上下左右,打赢游戏就给奖励,输了就惩罚,AI 自己慢慢学会通关;机器人不断尝试走路,摔倒得到负反馈,慢慢学会平稳行走。
二、按任务输出划分(拿到模型之后干什么)
- 分类任务 :预测离散类别。输出是类别。
- 📌例子:判断体检人员是否患病;判断水果是苹果还是橘子。
- 回归任务 :预测连续数值。输出是数字。
- 📌例子:预测未来一个月的销售额;预测人的身高。
- 聚类任务 :无监督,自动给数据分组。
- 📌例子:根据客户消费记录,把客户自动分成若干群体。
✔KNN 定位总结:
学习方式:有监督学习
可完成任务:分类任务、回归任务
一、KNN 算法简介
K‑近邻算法,英文全称为 K‑Nearest Neighbor,简称 KNN ,既可以做分类任务 ,也可以做回归任务。
✨核心思想
如果一个样本在特征空间中的 k 个最相似 (距离最近) 的样本中的大多数属于某一个类别,则该样本也属于这个类别。
通俗理解:根据你的邻居,推断你的类别。
二、KNN 执行流程
🔹KNN 分类流程
- 计算未知样本到每一个训练样本的距离
- 将训练样本按照距离从小到大升序排序
- 取出距离最近的 K 个训练样本
- 多数表决:统计 K 个样本中各个类别样本的数量
- 将未知样本判定为出现次数最多的类别
🔹KNN 回归流程
回归任务不再输出类别,输出预测数值:
- 计算未知样本到每一个训练样本的距离
- 将训练样本按照距离从小到大升序排序
- 取出距离最近的 K 个训练样本
- 计算这 K 个样本目标值的平均值
- 将平均值作为未知样本的预测结果
💡如何找到最近 k 个邻居?距离度量,sklearn 底层自动计算,默认使用欧式距离。
三、sklearn 中 KNN 的 API 使用
3.1 sklearn 库介绍
scikit‑learn(简称 sklearn)是 Python 中最主流、开源的机器学习工具库。
- 封装大量算法:分类、回归、聚类、降维、特征预处理、模型评估全部封装好,不需要手动手写算法底层。
- 统一 API 接口规范 :几乎所有模型都遵循
fit()训练、predict()预测的统一调用范式,学习一个算法,其他算法上手很快。 - 内置数据集:自带鸢尾花、波士顿房价等测试数据集,方便做算法练习。
- 适用场景:传统机器学习项目,不包含深度学习神经网络;深度学习一般使用 TensorFlow/PyTorch。
KNN 相关类都放在模块
sklearn.neighbors下面:
KNeighborsClassifier:KNN 分类模型KNeighborsRegressor:KNN 回归模型
通用模型使用四步套路:
- 导包:导入对应算法类
- 准备数据集:特征 X,标签 y
- 模型实例化 +
fit(X_train,y_train)训练 predict(X_test)做预测
3.2 KNN 分类代码示例(垃圾邮件模拟案例)
业务场景:模拟简单二分类,0 代表正常邮件,1 代表垃圾邮件,预测样本[4]是正常邮件还是垃圾邮件。
# 1.导包 此处导入knn分类模型
from sklearn.neighbors import KNeighborsClassifier
# 2.准备数据(此处我们模拟数据)
# x_train:训练集特征,方括号嵌套,即使只有1个特征,也要写成二维列表格式
x_train = [[0], [1], [2], [3]]
# x_test:待预测的测试样本
x_test = [[4]]
# y_train:训练集标签,0=正常邮件,1=垃圾邮件
y_train = [0, 0, 0, 1]
# 3.模型使用
# 3.1 创建分类模型
# n_neighbors=2:设置K值,取距离最近2个邻居
# 注意:KNN投票出现票数相同时,底层优先选择标签索引更小的类别
knn_model = KNeighborsClassifier(n_neighbors=2)
# 3.2 模型训练 fit(特征,标签)
# KNN是惰性学习,fit不会真正训练计算权重,只是保存全部训练数据集
knn_model.fit(x_train, y_train)
# 3.3 模型预测,传入待预测样本
y_pred = knn_model.predict(x_test)
# 3.4 打印预测结果
print(f"分类预测结果为:{y_pred}")
代码逐行解释
from sklearn.neighbors import KNeighborsClassifier:从 sklearn 的 neighbors 模块导入 KNN 分类器。x_train = [[0], [1], [2], [3]]:训练特征,sklearn 要求输入特征必须是二维数组,所以每个样本外面套一层[]。y_train = [0, 0, 0, 1]:训练集标签,一维列表,和训练特征一一对应。KNeighborsClassifier(n_neighbors=2):实例化模型,n_neighbors就是超参数 K,代表取几个邻居。.fit(x_train, y_train):传入训练特征与标签。KNN 惰性算法,这里仅保存数据,没有复杂运算。.predict(x_test):对测试样本做预测,此时才会计算距离,查找 K 个邻居,投票输出类别。
3.3 KNN 回归代码示例(房价预测模拟案例)
业务场景:根据特征值预测房价,输出连续数字,不是类别。
# 1.导包 此处导入knn回归模型
from sklearn.neighbors import KNeighborsRegressor
# 2.准备数据(此处我们模拟数据)
# x_train训练特征,二维格式
x_train = [[0], [1], [2], [3]]
# x_test待预测样本
x_test = [[4]]
# y_train标签,代表房价,单位万:0->70w,1->80w,2->100w,3->110w
y_train = [70, 80, 100, 110]
# 3.模型使用
# 3.1 创建回归模型,n_neighbors=3,取最近3个邻居
knn_model = KNeighborsRegressor(n_neighbors=3)
# 3.2 模型训练,保存训练数据
knn_model.fit(x_train, y_train)
# 3.3 模型预测,输出邻居目标值的平均值
y_pred = knn_model.predict(x_test)
# 3.4 打印预测结果
print(f"回归预测结果为:{y_pred}")
代码逐行解释
from sklearn.neighbors import KNeighborsRegressor:导入 KNN 回归模型。- 回归任务的标签
y_train不再是类别编号,是真实连续数值,本例代表房价。 KNeighborsRegressor(n_neighbors=3):实例回归模型,设置 K=3。.fit(x_train,y_train):同样惰性学习,保存训练数据。.predict(x_test):找到最近 K 个样本,计算这 K 个样本 y 值的平均值作为预测输出,不再做投票。
💡补充常用方法
.predict_proba():仅分类模型可用,输出每个样本属于各个类别的概率;回归模型没有这个方法。
四、距离度量
闵可夫斯基距离通用公式:
d₁₂ = 开 p 次方 (Σ |x₁ₖ − x₂ₖ|^p)
p 为可变参数,改变 p 得到不同距离:
表格
| 距离类型 | 参数 p | 特点 | 适用场景 |
|---|---|---|---|
| 欧氏距离 | p=2 | 勾股定理,直线距离 | 连续数值、低维空间(KNN 默认) |
| 曼哈顿距离 | p=1 | 各维度差值绝对值求和 | |
| 切比雪夫距离 | p→∞ | 只看最大维度差异 | 极值主导场景,路径规划 |
| 闵可夫斯基距离 | 任意 p | 通用公式 | 需要平衡多维度差异通用场景 |
- p=2 → 欧氏距离
- p=1 → 曼哈顿距离
- p 趋向无穷大 → 切比雪夫距离
KNN 算法高度依赖距离计算,特征的数值大小会直接影响距离结果,所以需要做特征预处理。
五、特征预处理:归一化 & 标准化
📌为什么要做预处理?
不同特征单位、数值量级差距巨大,某一个特征数值过大,会直接主导距离计算结果,算法无法学习其他特征。
例子:身高、体重、视力,体重数值远大于另外两个特征,计算距离时体重会起决定性作用。
1. 归一化 MinMaxScaler
把原始数据映射到 [min,max],默认映射到[0,1]。
公式:
X' = (x − min) / (max − min)
X'' = X' * (mx − mi) + mi
- 缺点:最大最小值极易受异常点干扰,鲁棒性差
- 适用:小数据、数据比较干净没有异常值场景
- sklearn API:
sklearn.preprocessing.MinMaxScaler(feature_range=(0,1))
2. 标准化 StandardScaler
将数据转换为均值为 0,标准差为 1的标准正态分布。
公式:
X' = (x − mean) / σ
- mean:该特征平均值
- σ:该特征标准差
示例代码:
from sklearn.preprocessing import StandardScaler
def dm03_StandardScaler():
#准备数据
data=[[90,2,10,40],
[60,4,15,45],
[75,3,13,46]]
#实例化标准化对象
transformer = StandardScaler()
#转换数据
data = transformer.fit_transform(data)
print(data)
print('transformer.mean_',transformer.mean_)
print('transformer.var_',transformer.var_)
- 特点:少量异常点对均值标准差影响很小,鲁棒性强
- 适用:大数据、有噪声数据,工业开发优先使用标准化
- sklearn API:
sklearn.preprocessing.StandardScaler()
📊归一化 vs 标准化对比
表格
| 预处理 | 抗异常点 | 适用场景 |
|---|---|---|
| 归一化 MinMaxScaler | 差,受最大最小值影响 | 小数据,数据无异常点 |
| 标准化 StandardScaler | 较好,少量异常点影响小 | 大数据,嘈杂数据,工业常用 |
六、整体知识梳理总结
- KNN 可以做分类、回归;核心逻辑依靠距离找最近邻居做预测。
- K 值是超参数;距离计算默认欧氏距离,底层是闵可夫斯基距离。
- KNN 对特征数值敏感,必须做特征预处理。
- 归一化容易被异常点破坏;标准化更适合工业大数据项目。
- sklearn 提供现成 API,直接调用 fit 训练、predict 预测。
补充:KNN 属于惰性学习算法,训练阶段没有真正训练模型,只是保存全部训练数据集,预测时才计算距离。