当前位置:  首页>> 技术小册>> Python机器学习基础教程(上)

2.3.2 k近邻(k-Nearest Neighbors, k-NN)

在机器学习领域,k近邻(k-Nearest Neighbors,简称k-NN)是一种既简单又强大的分类与回归方法。其核心思想在于“近朱者赤,近墨者黑”——即一个样本的类别(或回归值)应该与其在特征空间中最近的k个邻居的类别(或回归值)最为接近。k-NN算法不需要进行模型的显式训练,而是直接将整个训练集作为参考集,在预测时根据待预测样本与训练集中各样本的距离来找出最近的k个邻居,并基于这些邻居的信息进行预测。

2.3.2.1 k-NN算法原理

1. 距离度量

在k-NN算法中,首先需要定义一个合适的距离度量方式,用以计算样本之间的距离。最常用的距离度量是欧氏距离(Euclidean Distance),但在不同的问题背景下,也可以采用曼哈顿距离(Manhattan Distance)、闵可夫斯基距离(Minkowski Distance)等。对于二维空间中的两点$p_1(x_1, y_1)$和$p_2(x_2, y_2)$,它们的欧氏距离公式为:

d(p_1, p_2) = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}

扩展到n维空间,两点$p_1(x_1^{(1)}, x_1^{(2)}, \ldots, x_1^{(n)})$和$p_2(x_2^{(1)}, x_2^{(2)}, \ldots, x_2^{(n)})$之间的欧氏距离为:

d(p1, p_2) = \sqrt{\sum{i=1}^{n} (x_1^{(i)} - x_2^{(i)})^2}

2. k值选择

k-NN算法中的k是一个超参数,其选择对算法的性能有显著影响。k值较小时,模型对噪声较为敏感,容易发生过拟合;k值较大时,模型则变得简单,但可能会忽略掉一些重要的局部信息,导致欠拟合。在实际应用中,通常需要通过交叉验证等方法来确定最优的k值。

3. 投票机制(分类)

在分类任务中,k-NN算法通过多数投票的方式来确定待预测样本的类别。即,找出待预测样本的k个最近邻,然后统计这k个邻居中每个类别的出现次数,将待预测样本归类为出现次数最多的那个类别。

4. 平均值/中位数(回归)

在回归任务中,k-NN算法则通过计算k个最近邻的目标值(即因变量)的平均值或中位数来预测待预测样本的目标值。这种方法虽然简单,但在某些情况下能够取得不错的预测效果。

2.3.2.2 k-NN算法的优势与局限

优势

  1. 简单易懂:k-NN算法思想直观,易于实现和理解。
  2. 无需显式训练:与其他机器学习算法不同,k-NN算法不需要进行模型的显式训练,而是直接将训练集用于预测。
  3. 适用于多分类问题:k-NN算法天然支持多分类问题,且无需对算法本身进行任何修改。
  4. 对异常值不敏感(取决于k值):当k值较大时,单个异常值对预测结果的影响会减弱。

局限

  1. 计算成本高:随着训练集样本数量的增加,计算待预测样本与所有训练样本之间距离的成本会迅速上升,导致算法效率降低。
  2. 维度灾难:在高维空间中,由于数据点之间的相对距离趋于相等,k-NN算法的性能会显著下降。
  3. 对k值敏感:k值的选择对算法性能有重要影响,而k值的选择往往依赖于具体问题和先验知识。
  4. 易受不平衡数据集影响:在不平衡数据集中,k-NN算法可能会偏向于多数类样本,导致对少数类样本的预测效果不佳。

2.3.2.3 k-NN算法的优化策略

为了克服k-NN算法的上述局限,研究者们提出了多种优化策略:

  1. 数据预处理:通过特征选择、特征降维等方法降低数据的维度,提高算法效率并缓解维度灾难问题。
  2. 使用KD树、球树等数据结构:这些数据结构可以高效地查找最近邻,显著减少计算成本。
  3. 权重投票:在分类任务中,可以根据邻居与待预测样本之间的距离远近为其投票结果赋予不同的权重,使得距离更近的邻居对预测结果的影响更大。
  4. k值动态调整:根据数据的分布情况和预测任务的需求,动态调整k值以提高算法性能。
  5. 处理不平衡数据集:通过重采样、合成少数类样本等方法改善数据集的不平衡性,提高k-NN算法对少数类样本的预测能力。

2.3.2.4 实战案例:使用Python实现k-NN分类

在Python中,我们可以利用scikit-learn库中的KNeighborsClassifier类来实现k-NN分类。以下是一个简单的示例代码:

  1. from sklearn.datasets import load_iris
  2. from sklearn.model_selection import train_test_split
  3. from sklearn.neighbors import KNeighborsClassifier
  4. from sklearn.metrics import accuracy_score
  5. # 加载数据集
  6. iris = load_iris()
  7. X = iris.data
  8. y = iris.target
  9. # 划分训练集和测试集
  10. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
  11. # 创建k-NN分类器实例,设置k=3
  12. knn = KNeighborsClassifier(n_neighbors=3)
  13. # 训练模型
  14. knn.fit(X_train, y_train)
  15. # 预测测试集
  16. y_pred = knn.predict(X_test)
  17. # 计算准确率
  18. accuracy = accuracy_score(y_test, y_pred)
  19. print(f'Accuracy: {accuracy:.4f}')

在上述代码中,我们首先加载了鸢尾花(Iris)数据集,并将其划分为训练集和测试集。然后,我们创建了一个k-NN分类器实例,设置了k值为3,并使用训练集数据对模型进行了训练。最后,我们使用训练好的模型对测试集进行了预测,并计算了模型的准确率。

通过调整k值和其他参数,我们可以进一步探索k-NN算法在不同设置下的性能表现。同时,结合上述提到的优化策略,我们可以尝试对算法进行改进,以提高其在特定任务上的预测效果。


该分类下的相关小册推荐: