简介

KNN算法(K-Nearest Neighbors,K近邻算法),其基本思想是:如果一个样本在特征空间中的k个最相似的样本中的大多数属于某个类别,则该样本也属于这个类别。
有点像“物以类聚,人以群分”。

用途(有监督学习)

  • 分类问题(标签不连续):KNN算法可以用于分类问题,它根据样本的特征向量找到其k个最邻近的样本,并将这些样本的类别进行投票,选择出现次数最多的类别作为该样本的类别。
  • 回归问题(标签连续):KNN算法可以用于回归问题,它根据样本的特征向量找到其k个最邻近的样本,并将这些样本的输出值进行平均,作为该样本的输出值。

如何确定样本的相似性?

KNN算法的核心是计算样本之间的距离,距离的度量方法有很多种,常用的有欧氏距离、曼哈顿距离(街区距离)、切比雪夫距离等。
样本距离越近,则样本之间的相似性越高。

算法流程

1. 分类问题:

  1. 计算待分类样本与训练集中每个样本之间的距离。
  2. 按照距离升序排序。
  3. 取出距离最近的K个训练样本
  4. 进行多数表决(投票):统计K个样本中哪个类别的样本个数最多。
  5. 将未知样本的类别设置为多数表决的类别。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 导包
from sklearn.neighbors import KNeighborsClassifier
# 2. 准备数据集(测试集 和 训练集)
x_train = [[0], [1], [2], [3]] #训练集的特征数据,因为可以有多个特征,所以是二维数组
y_train = [0, 0, 1, 1] #训练集的标签数据,因为标签是离散的,所以是一维数组
x_test = [[5]] #测试集的特征数据

# 3. 创建模型对象
#estimator:估计器,模型对象,也可以用变量名 model 做接收
estimator = KNeighborsClassifier(n_neighbors=2)

# 4. 模型训练
#传入: 训练集的特征数据,训练集的标签数据
estimator.fit(x_train, y_train)

#5.模型预测
#传入: 测试集的特征数据,获取测试结果
y_pre = estimator.predict(x_test)

#6.打印预测结果
print(f'预测值为:{y_pre}')

2. 回归问题:

  1. 计算待预测样本与训练集中每个样本之间的距离。
  2. 按照距离升序排序。
  3. 取出距离最近的K个训练样本
  4. 计算K个训练样本的输出值的平均值。
  5. 把平均值作为未知样本的预测值。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 导包
from sklearn.neighbors import KNeighborsRegressor

#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]]

#3. 创建模型对象
estimator = KNeighborsRegressor(n_neighbors=3)

#4. 模型训练
estimator.fit(x_train, y_train)

#5. 模型预测
y_pre = estimator.predict(x_test)

#6. 打印预测结果
print(f'预测值为:{y_pre}')

K值的选择

K值过小:用较小邻域中的训练实例进行预测

  • 容易受到异常点的影响
  • 整体模型变得复杂(过度分析训练样本),容易发生过拟合

K值过大:用较大邻域中的训练实例进行预测

  • 受到样本均衡的问题
  • 整体模型变得简单(极端情况下,距离对预测结果影响太小,因为训练样本必然有一个种类是最多的,该种类决定了预测结果),容易发生欠拟合

如何对K值(超参数)进行调优?

  • 交叉验证法:将数据集分为训练集和验证集,在训练集上选择最优的K值,在验证集上评估模型效果
  • 网格搜索法:在K的范围内,尝试不同的K值,选择验证集上效果最好的K值