手把手教你掌握K近邻算法:从原理到实战

假设你要搬进新小区,想了解这里的居住环境。最直接的方式是什么?观察离你最近的5户邻居!如果3户有儿童游乐设施,2户有健身房,你会推测这是个适合家庭的小区。这正是K近邻(K-Nearest Neighbors, KNN)的核心思想——通过最近的K个"邻居"的特征来预测目标。相比线性回归的公式推导,KNN更像是数据版的"近朱者赤",让我们用代码实现这个有趣的算法。

本文将从算法原理、实现步骤、示例代码到结果展示,全方位带你走进KNN的世界。

文章结合博主个人经验编写,如有错误欢迎指正!

目录

1. 什么是K近邻算法?

2. 算法原理与步骤

2.1 算法原理

2.2 算法步骤

3. Python案例实战

3.1 导入必要的库

3.2 加载数据与数据预处理

3.3 构建并训练KNN模型

3.4 模型预测与评估

3.5 结果可视化

4. 总结


1. 什么是K近邻算法?

K近邻算法是一种基于实例的学习方法,也称为懒惰学习算法。其核心思想就是物以类聚,非常简单:

  • 对于一个待预测的样本,先计算它与训练集中所有样本的距离(常用欧氏距离、曼哈顿距离等),
  • 然后选取距离最近的K个样本,
  • 最后根据这K个邻居的信息(如类别、数值)来决定预测结果。

​简单来说就是,未知样本的类别由最近的K个邻居投票决定。比如医生判断肿瘤性质时,会参考相似患者的病理特征

例如,在分类问题中,可以通过多数投票的方式确定该样本的类别;而在回归问题中,则通常取这K个样本的平均值作为预测结果。

小提示:K值的选取对模型效果影响较大,通常需要通过交叉验证等方法来确定最优的K值。

2. 算法原理与步骤

2.1 算法原理

KNN 的核心在于距离度量。常见的距离计算方式包括:

  • 欧氏距离:适用于连续特征数据,计算公式为

d(x, y) = \sqrt{\sum_{i=1}^n (x_i - y_i)^2}

  • 曼哈顿距离:计算各维度差值绝对值之和

d(x, y) = \sum_{i=1}^n |x_i - y_i|

在实际应用中,特征缩放(如标准化或归一化)常常是必要的,因为不同尺度的特征会影响距离计算结果。

从上图可以看出,欧氏距离的决策边界呈现平滑连续的曲线形态,自然地划分数据点区域;曼哈顿距离的决策边界呈阶梯状(锯齿形),边界以水平、垂直方向的线段拼接而成。 

产生差异的原因:欧氏距离基于直线距离,均衡考虑各维度;曼哈顿距离基于轴方向的累加距离,强调单维度的绝对差异,最终使 KNN 分类的决策逻辑和边界形态产生显著差异。

2.2 算法步骤

  1. 数据准备:获取并预处理数据(缺失值处理、特征缩放等)。
  2. 计算距离:对于待预测样本,计算它与训练集中所有样本的距离。
  3. 选取最近邻:从训练集中选出距离最近的K个样本。
  4. 预测决策
    • 分类问题:采用多数投票,选出频次最高的类别作为预测结果。
    • 回归问题:计算K个邻居的均值,作为预测值。
  5. 评估模型:通过混淆矩阵、准确率、均方误差等指标评估模型性能。

3. Python案例实战

下面以一个经典的鸢尾花(Iris)数据集为例,使用Scikit-Learn实现KNN分类,并对模型进行可视化展示。

3.1 导入必要的库

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, confusion_matrix

3.2 加载数据与数据预处理

# 加载鸢尾花数据集
iris = datasets.load_iris()
X = iris.data  # 特征
y = iris.target  # 标签

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 特征缩放:使各特征均值为0,方差为1
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

3.3 构建并训练KNN模型

# 设置K值,例如K=5
k = 5
knn = KNeighborsClassifier(n_neighbors=k)
knn.fit(X_train, y_train)

3.4 模型预测与评估

# 模型预测
y_pred = knn.predict(X_test)

# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"模型在测试集上的准确率: {accuracy:.2f}")

# 输出混淆矩阵
cm = confusion_matrix(y_test, y_pred)
print("混淆矩阵:")
print(cm)

3.5 结果可视化

为了更直观地展示KNN分类效果,我们可以选取鸢尾花数据集中的两个特征(例如花萼长度与花萼宽度)绘制决策边界。

# 选取前两个特征进行可视化
X_vis = X[:, :2]
y_vis = y

# 划分训练集与测试集
X_train_vis, X_test_vis, y_train_vis, y_test_vis = train_test_split(X_vis, y_vis, test_size=0.3, random_state=42)

# 缩放特征
scaler_vis = StandardScaler()
X_train_vis = scaler_vis.fit_transform(X_train_vis)
X_test_vis = scaler_vis.transform(X_test_vis)

# 训练KNN模型
knn_vis = KNeighborsClassifier(n_neighbors=k)#默认是用欧式距离
knn_vis.fit(X_train_vis, y_train_vis)

# 定义绘图网格
h = .02  # 网格步长
x_min, x_max = X_train_vis[:, 0].min() - 1, X_train_vis[:, 0].max() + 1
y_min, y_max = X_train_vis[:, 1].min() - 1, X_train_vis[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                     np.arange(y_min, y_max, h))

# 预测网格中每一点的类别
Z = knn_vis.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

# 绘制决策边界和样本点
plt.figure(figsize=(8, 6))
plt.contourf(xx, yy, Z, alpha=0.4, cmap=plt.cm.RdYlBu)
plt.scatter(X_train_vis[:, 0], X_train_vis[:, 1], c=y_train_vis, s=50, edgecolor='k', cmap=plt.cm.RdYlBu)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 指定中文字体,如黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
plt.title(f"K近邻算法决策边界 (K={k})")
plt.xlabel("花萼长度(标准化后)")
plt.ylabel("花萼宽度(标准化后)")
plt.show()

可视化结果如下

从这幅图可以直观地看出,KNN(K=5)算法在仅使用前两个特征(花萼长度、花萼宽度)时,如何将整个特征平面划分为不同的分类区域。每一种背景颜色代表了模型在该区域内对新样本的预测类别,而散点则是训练集中已知类别的样本。具体来说

  • 背景色区域

    • 红色、蓝色、黄色三个区域分别对应了KNN模型预测的三种类别(对应鸢尾花数据集的三类:Setosa、Versicolor、Virginica)。
    • 每一个区域内,如果你在这个区域随机选取一个点作为测试样本,KNN 会将它判定为对应的那种颜色所代表的类别。
  • 决策边界

    • 不同颜色交界处就是 KNN 的决策边界,表示在这些边界上,如果再稍微移动一点点位置,就可能被划分到相邻的另一类。
    • 由于 KNN 是基于“最近邻”原理(并且特征已经标准化),所以决策边界往往会比较灵活,并且不是线性或简单的分割方式,而是根据训练样本的分布呈现出较为“蜿蜒”的形状。
  • 散点分布

    • 图中带黑色边框的散点是训练样本,散点的颜色代表它们的真实类别。可以观察到,绝大多数散点都落在(或非常接近)与其颜色相匹配的背景区域中,说明模型在当前训练数据上的表现不错。
    • 若有散点分布在与其颜色不匹配的背景区域,通常说明这个样本可能在这两个类别的特征空间里有重叠或者噪声。
  • K 值的影响

    • 本例中 K=5,表示在分类时,会参考“最近”的 5 个样本进行多数投票。若 K 过小,决策边界会变得非常“曲折”,对噪声敏感;若 K 过大,决策边界又会过于平滑,可能导致对局部结构不敏感
    • 从图中可以看到 K=5 对该数据集划分出的决策边界基本能够把各类区分开,表明该参数在这个场景下相对合适。

4. 总结

本文通过对K近邻算法的详细讲解和Python实战案例,为大家展示了该算法从原理到应用的完整流程。

KNN算法虽然简单,但在很多实际问题中表现出色。

希望这篇文章能帮助你更好地理解和掌握K近邻算法!

如果本文对您有所启发,期待您的点赞关注!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值