机器学习算法 —— K近邻(KNN分类)
🌟欢迎来到 我的博客 —— 探索技术的无限可能!
目录
- KNN的介绍和应用
-
-
KNN的介绍
-
-
- KNN建立过程
-
- 类别的判定
-
-
KNN的优点
-
KNN的缺点
-
KNN的应用
-
实战 K-近邻分类 数据集 —— K-近邻分类 库函数加载 数据读取 模型训练与结果可视化 理论基础概述
-
莺尾花数据集 —— 邻近分类方法
-
- 库函数引入
-
-
数据导入与分析
-
模型训练阶段
-
模型预测与结果展示
- KNN回归
KNN的介绍和应用
KNN的介绍
K近邻法(全称为K-近邻分类器)是一种基于实例的学习方法,在机器学习领域中被广泛应用于分类和回归问题中。该算法的核心概念在于通过测试样本与训练集中的各个样本之间的相似性来推断未知样例所属的类别或预测其数值特征。具体而言,在分类任务中算法会根据测试样本与训练集中各个样本之间相似程度较高的前k个邻居所对应的类别进行投票;而对于回归问题则会将这些邻居的数据特征取平均值作为预测结果的基础依据。在实际应用中选择合适的相似度评估指标对于模型性能有着至关重要的影响。
k值也可以代表我们的模型复杂度水平,在这种情况下,k值越小时,模型对复杂性的适应能力就越差,容易导致过拟合现象的发生。(具体而言,我们可以用少量树的样本来绝对地评估这一预测结果,这很容易引入偏见性,这就是所谓的过拟合现象)。另一方面,我们知道,k值越大时,学习到的估计误差会随之减小,但与此同时,近似的偏差也会逐渐增大。
kNN(k-nearest neighbors)是机器学习中的一个重要算法,在中文中常被称作K近邻算法。我们经常听说这样一个故事:通过掌握一个人五个最要好的朋友的经济状况来推断其整体经济水平,并将这五个人的经济指标取平均作为其经济水平的评估标准。这也正是kNN算法的核心思想所在。

如上图所示,则绿色圆需确定归属:归为红色三角形一类还是划分为蓝色四方形类别?当K取不同值时,请注意以下情况:若K=3,则因红色三角形占比率为2:3;此时绿色圆将被视为属于红色三角形类别;而当K=5时,则因蓝色四方形的比例达到3:5;因此绿色圆最终会被分类到蓝色四方形类别中。
1) KNN建立过程
- 对于给定测试样本,计算其与训练集中所有样本之间的距离。
- 确定距离当前最近的K个训练样本,并将其视为该测试样例的近邻。
- 根据这K个最近邻居所属类别的分布情况来判定该测试样例所属类别。
2) 类别的判定
①投票决定,少数服从多数。取类别最多的为测试样本类别。
加权投票机制中采用了一种基于计算所得的距离远近来进行邻近投票赋予权重的方式。该方法通过将权重设定为距离平方分之一来实现对邻近度更高的票力建立更高权重的目标
KNN的优点
- 直观且易于掌握:KNN算法的核心思想简单明了,在理解与实现上都十分便捷。它不仅便于理解而且实现相对简便,在参数设置与训练时间上也具有显著优势。
- 适合多种应用场景:该算法适合用于分类与回归两种主要任务,在实际应用中展现出很强的适应性。
- 不受数据分布规律的影响:KNN方法不受数据分布规律的影响特点使其能够在不同类型的输入数据上获得良好效果。
- 面对新增数据时:该方法在面对新增的数据样本时能够即时利用新增的数据进行预测分析而不必重新训练模型即可完成相关计算需求
KNN的缺点
- 计算开销大:面对海量的数据样本,在计算每个新样本与训练集中所有样本之间的距离时会耗时较长,并因此降低了预测效率。
- 存储需求大:KNN算法需要存储整个训练集的所有样本信息,在处理大数据集时带来了较高的内存占用。
- 易受干扰:该算法容易受到异常值或噪声样本的影响,在实际应用中可能降低分类准确率。
- 高维挑战:当处理高维空间中的问题时(如图像识别),KNN算法因维度灾难而难以有效工作。
KNN的应用
虽然看似简单,但KNN算法却蕴含着深刻的思想:相似的事物往往会被归为一类。这种简单的模型在分类和回归任务中都能发挥作用,并且还可以用于数据预处理中的缺失值填充工作。值得注意的是,在许多机器学习场景中,默认情况下KNN算法因其良好的可解释性而常被用作基准模型选择之一:对于每一个预测结果我们都可以清晰地理解其背后的原因所在。在推荐系统领域中也存在着对KNN算法的间接应用:例如,在文章推荐系统中我们可以将与目标用户A最接近的k位用户推荐其尚未阅读的文章内容作为候选列表
机器学习领域中,在该领域占据核心地位的数据至关重要,并有一句名言道:“数据决定了任务的最大可实现效果, 而模型的目标则是尽可能地逼近这一上限”。
能够看到优质的数据极为重要;然而由于多种原因存在,并非总是能得到完整的高质量数据集;但若能成功地填补这些缺失值,则将有助于提升数据质量,并最终训练出更加鲁棒的模型;接下来我们将重点探讨KNN方法在分类任务中的应用及其在回归分析和缺失值填补方面的具体操作与实现方法
实战
KNN分类
数据集 —— KNN分类
库函数导入
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.neighbors import KNeighborsClassifier
from sklearn import datasets
数据导入
采用莺尾花数据集的前两维特征有助于进行数据可视化
iris = datasets.load_iris()
X = iris.data[:, :2]
y = iris.target
模型训练&可视化
k_list = [1, 3, 5, 8, 10, 15]
h = .02
# 创建不同颜色的画布
cmap_light = ListedColormap(['orange', 'cyan', 'cornflowerblue'])
cmap_bold = ListedColormap(['darkorange', 'c', 'darkblue'])
plt.figure(figsize=(15,14))
# 根据不同的k值进行可视化
for ind,k in enumerate(k_list):
clf = KNeighborsClassifier(k)
clf.fit(X, y)
# 画出决策边界
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
# 根据边界填充颜色
Z = Z.reshape(xx.shape)
plt.subplot(321+ind)
plt.pcolormesh(xx, yy, Z, cmap=cmap_light)
# 数据点可视化到画布
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold,
edgecolor='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("3-Class classification (k = %i)"% k)
plt.show()

原理简析
如果采用较小的K值,则等同于在小范围内使用训练实例进行预测。例如,在k=1的情况下,在分界点附近的数据容易受到局部区域显著影响(如图中所示),因为蓝色区域中仍存在部分绿色块体(这主要是由于数据过于局部敏感)。而当k=15时,在这种情况下不同数据点会根据颜色分布基本分离开来,并且此时在进行预测时会直接落入相应的区域中(模型因此表现出更强的稳定性)。
莺尾花数据集 —— KNN分类
库函数导入
import numpy as np
# 加载莺尾花数据集
from sklearn import datasets
# 导入KNN分类器
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
数据导入&分析
# 导入莺尾花数据集
iris = datasets.load_iris()
X = iris.data
y = iris.target
# 得到训练集合和验证集合, 8: 2
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
模型训练
这里我们设置参数k(n_neighbors)=5, 使用欧式距离(metric=minkowski & p=2)
clf = KNeighborsClassifier(n_neighbors=5, p=2, metric="minkowski")
clf.fit(X_train, y_train)

模型预测&可视化
预测
X_pred = clf.predict(X_test)
acc = sum(X_pred == y_test) / X_pred.shape[0]
print("预测的准确率ACC: %.3f" % acc)

这里用表格进行可视化KNN的训练和预测过程:
1.训练数据[表格对应list]
| feat_1 | feat_2 | feat_3 | feat_4 | label |
|---|---|---|---|---|
| 5.1 | 3.5 | 1.4 | 0.2 | 0 |
| 4.9 | 3. | 1.4 | 0.2 | 0 |
| 4.7 | 3.2 | 1.3 | 0.2 | 0 |
| 4.6 | 3.1 | 1.5 | 0.2 | 0 |
| 6.4 | 3.2 | 4.5 | 1.5 | 1 |
| 6.9 | 3.1 | 4.9 | 1.5 | 1 |
| 5.5 | 2.3 | 4. | 1.3 | 1 |
| 6.5 | 2.8 | 4.6 | 1.5 | 1 |
| 5.8 | 2.7 | 5.1 | 1.9 | 2 |
| 7.1 | 3. | 5.9 | 2.1 | 2 |
| 6.3 | 2.9 | 5.6 | 1.8 | 2 |
| 6.5 | 3. | 5.8 | 2.2 | 2 |
2.knn.fit(X, y)的过程可以简单认为是表格存储
| feat_1 | feat_2 | feat_3 | feat_4 | label |
|---|---|---|---|---|
| 5.1 | 3.5 | 1.4 | 0.2 | 0 |
| 4.9 | 3. | 1.4 | 0.2 | 0 |
| 4.7 | 3.2 | 1.3 | 0.2 | 0 |
| 4.6 | 3.1 | 1.5 | 0.2 | 0 |
| 6.4 | 3.2 | 4.5 | 1.5 | 1 |
| 6.9 | 3.1 | 4.9 | 1.5 | 1 |
| 5.5 | 2.3 | 4. | 1.3 | 1 |
| 6.5 | 2.8 | 4.6 | 1.5 | 1 |
| 5.8 | 2.7 | 5.1 | 1.9 | 2 |
| 7.1 | 3. | 5.9 | 2.1 | 2 |
| 6.3 | 2.9 | 5.6 | 1.8 | 2 |
| 6.5 | 3. | 5.8 | 2.2 | 2 |
3.knn预测函数的作用是计算输入样本与训练集中各个样本之间的距离
在这里我们采用欧氏距离来衡量输入样本与训练集中的各个样本之间的距离, 预测过程如下

1: 计算x和所有训练数据的距离
| feat_1 | feat_2 | feat_3 | feat_4 | 距离 | label |
|---|---|---|---|---|---|
| 5.1 | 3.5 | 1.4 | 0.2 | 0.14142136 | 0 |
| 4.9 | 3. | 1.4 | 0.2 | 0.60827625 | 0 |
| 4.7 | 3.2 | 1.3 | 0.2 | 0.50990195 | 0 |
| 4.6 | 3.1 | 1.5 | 0.2 | 0.64807407 | 0 |
| 6.4 | 3.2 | 4.5 | 1.5 | 3.66333182 | 1 |
| 6.9 | 3.1 | 4.9 | 1.5 | 4.21900462 | 1 |
| 5.5 | 2.3 | 4. | 1.3 | 3.14801525 | 1 |
| 6.5 | 2.8 | 4.6 | 1.5 | 3.84967531 | 1 |
| 5.8 | 2.7 | 5.1 | 1.9 | 4.24617475 | 2 |
| 7.1 | 3. | 5.9 | 2.1 | 5.35070089 | 2 |
| 6.3 | 2.9 | 5.6 | 1.8 | 4.73075047 | 2 |
| 6.5 | 3. | 5.8 | 2.2 | 5.09607692 | 2 |
2: 根据距离进行编号排序
| 距离升序编号 | feat_1 | feat_2 | feat_3 | feat_4 | 距离 | label |
|---|---|---|---|---|---|---|
| 1 | 5.1 | 3.5 | 1.4 | 0.2 | 0.14142136 | 0 |
| 3 | 4.9 | 3. | 1.4 | 0.2 | 0.60827625 | 0 |
| 2 | 4.7 | 3.2 | 1.3 | 0.2 | 0.50990195 | 0 |
| 4 | 4.6 | 3.1 | 1.5 | 0.2 | 0.64807407 | 0 |
| 6 | 6.4 | 3.2 | 4.5 | 1.5 | 3.66333182 | 1 |
| 8 | 6.9 | 3.1 | 4.9 | 1.5 | 4.21900462 | 1 |
| 5 | 5.5 | 2.3 | 4. | 1.3 | 3.14801525 | 1 |
| 7 | 6.5 | 2.8 | 4.6 | 1.5 | 3.84967531 | 1 |
| 9 | 5.8 | 2.7 | 5.1 | 1.9 | 4.24617475 | 2 |
| 12 | 7.1 | 3. | 5.9 | 2.1 | 5.35070089 | 2 |
| 10 | 6.3 | 2.9 | 5.6 | 1.8 | 4.73075047 | 2 |
| 11 | 6.5 | 3. | 5.8 | 2.2 | 5.09607692 | 2 |
3: 我们设置k=5,选择距离最近的k个样本进行投票
| 距离升序编号 | feat_1 | feat_2 | feat_3 | feat_4 | 距离 | label |
|---|---|---|---|---|---|---|
| 1 | 5.1 | 3.5 | 1.4 | 0.2 | 0.14142136 | 0 |
| 3 | 4.9 | 3. | 1.4 | 0.2 | 0.60827625 | 0 |
| 2 | 4.7 | 3.2 | 1.3 | 0.2 | 0.50990195 | 0 |
| 4 | 4.6 | 3.1 | 1.5 | 0.2 | 0.64807407 | 0 |
| 6 | 6.4 | 3.2 | 4.5 | 1.5 | 3.66333182 | 1 |
| 8 | 6.9 | 3.1 | 4.9 | 1.5 | 4.21900462 | 1 |
| 5 | 5.5 | 2.3 | 4. | 1.3 | 3.14801525 | 1 |
| 7 | 6.5 | 2.8 | 4.6 | 1.5 | 3.84967531 | 1 |
| 9 | 5.8 | 2.7 | 5.1 | 1.9 | 4.24617475 | 2 |
| 12 | 7.1 | 3. | 5.9 | 2.1 | 5.35070089 | 2 |
| 10 | 6.3 | 2.9 | 5.6 | 1.8 | 4.73075047 | 2 |
| 11 | 6.5 | 3. | 5.8 | 2.2 | 5.09607692 | 2 |
4: k近邻的label进行投票
nn_labels = [0, 0, 0, 0, 1] --> 得到最后的结果0。
