Python 中的 k-最近邻 (kNN) 算法

2025年1月5日 | 阅读 26 分钟

机器学习基础

退后一步,快速回顾机器学习的总体概念,以帮助您入门。在本节中,您将了解机器学习的核心概念以及 kNN 方法如何与其他机器学习技术联系起来。

机器学习的主要目标是训练一个模型来识别任何历史数据中的模式,以便它可以在未来对相似数据重复这些模式。下面是一个展示机器学习基本步骤的流程图。

The k-nearest Neighbours (kNN) Algorithm in Python

这张图显示了一个拟合到历史数据的机器学习模型。左侧显示了初始观测值,包括高度、宽度和形状测量。三角形、十字和星形构成了这些形状。

图的各个部分都包含这些形状。您可以看到右侧如何将这些初始观测值转换为一个决策规则。您需要知道新观测值的宽度和高度才能确定它属于哪个方块。它将采取什么形状取决于它落在哪个方块。

为了达到这个目标,可以应用几种替代模型。可以用来描述数据点的数学公式称为模型。线性模型是一个例子,它使用一个由方程 y = ax + b 表示的线性函数。

当您估计或拟合模型时,一个算法会确定固定参数的最佳值。线性模型的参数是 a 和 b。幸运的是,您不必从头开始创建这些估计方法。杰出的数学家们已经找到了它们。

一旦模型被估计出来,它就可以作为一个数学公式,通过输入自变量的值来预测目标变量的值。从高层次来看,这就是所有发生的事情!

kNN 的区别特征

现在您知道了机器学习是如何工作的,下一步就是理解为什么现在有如此多的模型可供选择。使用线性模型进行回归称为线性建模。

虽然它有时会产生准确的预测,但线性回归并非总是有效。因此,数学家们已经开发出各种额外的机器学习模型供您使用。k-最近邻算法就是其中之一。

这些模型中的每一个都有独特的特征。如果您从事机器学习工作,您应该充分理解每一个模型,以便将合适的模型应用于问题。下一步是检查 kNN 与其他机器学习模型的比较,以理解为什么以及何时使用 kNN。

这种监督式机器学习算法称为 kNN。机器学习算法的第一个定义特征是监督式模型和非监督式模型之间的区别。问题陈述区分了监督式和非监督式模型。

在监督式模型中,有两种不同类型的变量。

  1. 目标变量有时被称为因变量或 y 变量。
  2. 自变量,有时称为“x 变量”或“解释变量”。

您希望预测的变量称为目标变量。您无法提前预测它,它取决于自变量。自变量是您能够提前知道的。您可以通过将它们代入方程来预测所需的变量。这与 y = ax + b 的情况类似。

数据点的形状是前图和本节后续图中的目标变量,而高度和宽度是自变量。下图说明了监督式学习是如何工作的。

The k-nearest Neighbours (kNN) Algorithm in Python

此图中的每个数据点都有高度、宽度和形状。有三角形、十字和星形。右侧显示了机器学习模型可能已学会的决策规则。

在这种情况下,用十字标记的观测值又高又不宽。高大和宽阔都描述了星形。三角形可能又高又窄,但它们都很矮。该模型已经学会了一个决策规则,该规则仅使用观测值的高度和宽度来确定它更可能是十字、星形还是三角形。

在非监督式模型中,目标变量和自变量没有被分开。非监督式学习旨在通过确定数据项的相似程度来对它们进行分组。

尽管您可能永远无法确定分组的数据项是否真正属于同一组,但如示例所示,如果分组有意义,它在实践中可能很有用。下图说明了非监督式学习是如何工作的。

The k-nearest Neighbours (kNN) Algorithm in Python

此图中的观测值不再由不同的形状表示。它们都是圆圈。然而,根据点的分离程度,它们仍然可以分成三类。在这种特定情况下,可以根据分离它们的空白空间来区分三组点。

kNN 算法是一种监督式机器学习模型。换句话说,它基于一个或多个自变量来预测目标变量。

阅读《Python 中的 K-均值聚类:实用指南》以了解更多关于非监督式机器学习方法的信息。

kNN 是一种非线性学习算法

模型估计非线性关系的能力是影响机器学习方法的第二个重要因素。

使用直线或超平面进行预测的模型称为线性模型。模型显示在图片中,是一条连接位置的直线。线性模型的标准示例是 y = ax + b。在下面的图中,您可以看到线性模型如何拟合测试数据。

The k-nearest Neighbours (kNN) Algorithm in Python

此图左侧显示的数据点为星形、三角形和十字。右侧显示了一个可以区分三角形和非三角形的线性模型。决策线是一条直线。三角形仅存在于直线下方;直线上的所有点都是非三角形。

前面的图形需要绘制为添加了额外的自变量的维度,从而得到一个包含形状的立方体。但是,一条直线无法将立方体分成两半。在三维空间中,超平面是直线等价物。因此,超平面(在二维空间中恰好是一条直线)代表了一个线性模型。

非线性模型使用除直线以外的方法将实例分成组。决策树,一系列长 if...else 语句,是一个著名的例子。在非线性图中,if...else 语句可以让你设计任意形状的方块。下面的图形显示了一个用于示例数据的非线性模型。

The k-nearest Neighbours (kNN) Algorithm in Python

此图演示了决策的非线性。三个方块构成了决策规则。新数据点的预期形状将由它所在的方块决定。记住,使用一条直线一次只能拟合部分:需要两条直线。可以使用以下 if...else 语句来重现此模型。

如果以上条件都不成立,则该数据点是一个星形。如果该数据点的**高度**较低,则它是一个三角形。如果该数据点的**宽度**较低,则它是一个十字。

kNN 这样的模型是非线性模型。您将在本课程的后面部分回到计算模型的精确方法。

在分类和回归方面,kNN 都是一种监督式学习器。

监督式机器学习算法可以根据它们可以预测的目标变量的类型分为两类。

  1. 具有分类目标变量的预测任务是分类。分类模型学习如何对每个新观测值进行分类。没有中间地带;这个类别可以是正确的,也可以是错误的。鸢尾花数据集是一个著名的分类示例,它使用植物的物理测量值来推断其物种。逻辑回归是可用于分类的著名算法。
  2. 回归的预测目标使用数值目标变量。Kaggle 上的房屋价格挑战是一个著名的回归实例。机器学习竞赛的参与者试图使用各种自变量来预测房屋的销售价值。

您可以在下面的图形中看到前面示例中的回归和分类的示例。

The k-nearest Neighbours (kNN) Algorithm in Python

此图像的左侧是分类。观测值的形状(一个分类变量)是目标变量。右侧是回归。变量的目标是一个数字。即使两个案例对决策规则的解释可能相同,但它们是不同的。

分类为单次预测提供二元结果,而回归具有连续尺度的误差。由于数值误差度量更有用,因此许多分类模型都会预测类别以及属于每个类别的概率。

有些模型可以进行分类,有些只能进行回归,还有些可以同时进行。kNN 算法可以轻松处理分类和回归。在本课程的下一部分,您将确切了解这如何运作。

快速且可解释的 kNN

模型复杂性必须被视为描述机器学习模型的最后一个标准。人工智能,特别是机器学习,目前正处于蓬勃发展的状态,并被用于各种具有挑战性的任务,包括文本、图像和语音处理,以及自动驾驶汽车。

k-最近邻模型可以学习比更复杂模型(如神经网络)更复杂的东西。毕竟,那些复杂的模型是非常强大的学习者。但是请注意,这种复杂性是有代价的。您将花费更多精力来开发模型以适应您的预测。

为了拟合更复杂的模型,您还需要更多的数据,而数据并非总是可用的。即使这种解释有时很有益,但更复杂的模型对我们人类来说也更难理解。

kNN 模型的力量就在于此。它相对容易构建,并且允许用户理解和分析模型内部发生的事情。因此,kNN 是许多不需要极其复杂过程的机器学习用例的绝佳模型。

kNN 的问题

关于 kNN 算法的缺点,应该坦诚相待。如前所述,其主要弱点是 kNN 无法适应自变量和因变量之间极其复杂的关系。kNN 在计算机视觉和自然语言处理等高级任务中不太可能成功。

通过添加其他机器学习方法,您可以最大化 kNN 的性能。您将在课程的最后一部分研究一种称为装袋(bagging)的方法,这是一种提高预测结果的策略。但是,无论如何校准,kNN 在一定复杂度下可能都不如替代模型有效。

使用 kNN 估算海蛞蝓的年龄。

在本课程的其余部分,您将以鲍鱼数据集为例,跟随代码部分进行学习。该集合包含许多鲍鱼的年龄指标。仅供参考,鲍鱼的外观如下。

鲍鱼问题的陈述

通过剖开鲍鱼的壳并计算其上的环数,可以了解其年龄。鲍鱼数据集包含了许多鲍鱼的年龄测量和其他物理测量数据。

该项目旨在创建一个模型,仅能根据鲍鱼的物理特征来估计其年龄。通过这样做,科学家们可以在不剖开鲍鱼壳并计算其环数的情况下计算其年龄。

为了获得最准确的预测分数,您将使用 kNN。

正在导入鲍鱼数据集。

您将在本课程中处理鲍鱼数据集。虽然您可以下载它并使用 pandas 将数据导入 Python,但让 pandas 自动执行会更快。

建议使用 Anaconda 安装 Python 以便跟随教程代码。Anaconda 发行版包含许多重要的数据科学包。请参阅《Windows 上设置 Python 进行机器学习》以获取有关环境设置的额外帮助。

以下是如何使用 pandas 导入数据。

说明

此代码在最初导入数据后使用 pandas 读取数据。要直接从 Internet 下载内容,您必须将路径指定为 URL。

您可以通过一个简单的检查,如下所示,来确保您已正确导入数据。

这应该会显示导入到 Python 中的鲍鱼数据集的 pandas DataFrame 的前五行。如您所见,列名仍需添加。鲍鱼。名字文件在 UCI 机器学习存储库中包含这些名称。以下是如何将它们包含在您的 DataFrame 中。

导入的数据更有意义了。不过,还有一件事您应该做:删除 Sex 列。当前实验的目标是使用物理测量来估计鲍鱼的年龄。您应该从数据集中删除 Sex 列,因为它不是严格的物理因素。使用 .drop,您可以删除 Sex 列。

使用此代码,Sex 列被删除,因为它对建模过程没有贡献。

鲍鱼数据集的统计分析

在使用机器学习时,您必须了解您使用的数据。这里快速看一下一些探索性统计和图表,而无需深入细节。

Rings 是本练习的目标变量,所以您应该从那里开始。直方图将提供对预期年龄范围的快速有用概览。

此代码使用 pandas 的绘图功能创建了一个带有十五个 bin 的直方图。进行了一些测试后决定使用十五个 bin。在确定 bin 的数量时,通常的目标是每个 bin 中的观测值既不过多也不过少。如果 bin 的数量过多或过少,直方图可能会显得不平滑,从而掩盖一些模式。下图显示了直方图。

The k-nearest Neighbours (kNN) Algorithm in Python

直方图显示,虽然最多可以有二十五个环,但该数据集中大多数鲍鱼的环数在五个到十五个之间。在这个数据集中,年长的鲍鱼代表性不足。这很有意义,因为由于自然过程,年龄分布通常是这样偏斜的。

找出哪些因素(如果有)与年龄显示出高度相关性是第二项相关研究领域。独立变量与您的目标变量之间的高度相关性将是物理测量与年龄相关的积极迹象。

完整的相关矩阵显示在 correlation_matrix 中。与目标变量 Rings 的相关性最重要。这些相关性可以如下获得。

现在考虑 Rings 与其他因素的相关得分。它们越接近 1,联系就越多。

成熟鲍鱼的形态特征与其年龄之间至少存在一些关联,如果不是强关联的话。非常高的相关性表明建模方法将很简单。您需要进行实验以找出 kNN 算法的结果。

使用 pandas 可以打开更多数据调查的机会。有关使用 pandas 进行数据探索的更多信息,请参阅《使用 Pandas 和 Python 探索您的数据集》。

Python 教程:一步一步从头开始 kNN

在本课部分,您将学习 kNN 算法的内部工作原理。您必须理解该算法的两个主要数学组成部分。您将从一个简单的 kNN 算法之旅开始热身。

kNN 算法的简单解释

与其他的机器学习方法相比,kNN 算法是不同寻常的。正如您已经看到的,每种机器学习模型都有一个独特的公式需要估计。k-最近邻方法是独特的,因为这个公式是在预测时计算的,而不是在拟合时计算。大多数其他模型都不同。

顾名思义,kNN 方法在引入新数据点时,首先会找到新数据点最近的邻居。然后使用这些邻居的值来预测新数据点的值。

考虑您的邻居作为此工作原理的一个简单示例。通常,您和您的邻居有相似的兴趣。他们很可能属于与您相同的社会经济群体。他们可能在同一个领域工作,送孩子去您的学校等等。然而,这种方法可能不适用于其他任务。例如,通过查看邻居的喜好颜色来确定您喜欢的颜色将是荒谬的。

kNN 技术基于这样一个理念:您可以根据数据点的邻居来预测其属性。这种预测在某些情况下可能有效,而在其他情况下则无效。接下来将讨论数据点“最近”的数学定义,以及将多个邻居组合成一个预测的方法。

用数学方式解释“最近”的距离

欧几里得距离是一种数学距离描述,可用于查找最接近您需要预测的点的数据点。

要得到这个定义,您需要先理解两个向量之间的差异意味着什么。这是一个例子。

The k-nearest Neighbours (kNN) Algorithm in Python

这张图可能有两个数据点:蓝色点位于 (2,2),绿色点位于 (4,4)。让我们首先组合两个向量来获得它们之间的距离。从点 (4,2) 到点 (4,4),向量 a 行进,从点 (4,2) 到点 (2,2),向量 b 行进。彩色的点代表它们的头部。正如您所看到的,它们成 90 度角。

向量 c 连接向量 a 的头部和向量 b 的头部,区分了这两个向量。向量 c 的长度代表您的两个数据点之间的距离。

范数(norm)指的是向量的长度。向量的模由范数表示,这是一个正值。欧几里得公式可用于确定向量的范数。

The k-nearest Neighbours (kNN) Algorithm in Python

这个公式使用每个维度中平方差的平方根以及距离来计算距离。为了在此情况下确定数据点之间的间隔,您应该计算差向量 C 的范数。

您必须认识到您的数据点是向量才能将其应用于您的数据。通过确定差向量的范数来计算它们之间的距离。

Python 可以使用 NumPy 函数 `np.linalg.norm()` 来计算这一点。这是一个例子。

在此代码块中,您将数据点定义为向量。然后使用两个数据点之间的差值来计算 `norm()`。这样,多维位置之间的距离就立即确定了。即使它们是多维的,点之间的距离仍然是一个标量或单个数字。

有关更多数学信息,请查看勾股定理,了解欧几里得距离公式的创建方式。

找到 k 个最近邻

现在您知道如何计算任何两点之间的距离,您就可以利用这些知识来找到最接近您要基于其进行预测的点。

您需要找到的邻居数量由 k 表示。k 的最小值必须为 1。这意味着仅使用一个邻居进行预测。数据点的数量是最大值。这意味着使用所有邻居。用户决定其值应该是多少。您将在本课程的最后一部分学习如何使用优化工具来完成此操作。

回到鲍鱼数据集并使用 NumPy 查找最近的邻居。您首先需要使用 `.values` 属性将 pandas DataFrame 转换为 NumPy 数组,因为正如您所见,您需要在自变量向量上指定距离。

此代码块创建了两个对象 X 和 y,它们现在包含您的数据。您的模型的自变量称为 X,因变量称为 y。X 使用大写字母,而 y 使用小写字母。因为数学符号通常使用大写字母表示矩阵,小写字母表示向量,所以这在机器学习算法中很常见。

现在,您可以使用 k=3 的 kNN 对一个具有物理测量值的新鲍鱼进行如下预测。

The k-nearest Neighbours (kNN) Algorithm in Python

可以按如下方式创建此数据点的 NumPy 数组。

最后一步是使用以下代码计算此新数据点与鲍鱼数据集中每个数据点之间的距离。

以下是与您的 `new_data_point` 最近的三个邻居。在下一段中,您将学习如何将这些邻居转换为估计值。

多个邻居投票或平均投票

在确定了鲍鱼三个最近邻居的索引后,您需要将它们合并起来,为您的新数据点创建一个预测。

您需要先了解这三个邻居的真实情况。

您现在可以根据这三个邻居的值对您的新数据点进行预测。对于回归和分类,将邻居合并成一个预测的方法不同。

标准回归值

回归问题中的目标变量是一个数字。您可以通过对多个邻居的目标变量值取平均值来将多个邻居的预测合并成一个。例如,您可以这样做。

您将收到一个预测分数 10。因此,您的新数据点的 3-最近邻预测是 10。您想要多少个新鲍鱼,情况也是如此。

分类方法

分类问题中的目标变量是分类的。如前所述,无法计算分类变量的平均值。例如,预测的三个汽车制造商的平均值是什么?无法说明。平均值不能用于类预测。

相反,您使用众数(mode)进行分类。出现频率最高的值是众数。这意味着在添加了所有邻居的类别后,您会保留最普遍的类别。最常出现在邻居中的值就是预测。

如果存在多个众数,则有几种可能的解决方案。可以从其他获胜者中随机选择最终获胜者。如果最终决定基于邻居之间的距离,则将保留最近邻居的众数。

您可以使用 SciPy 的 `mode()` 方法来确定众数。由于鲍鱼示例不是分类案例,因此以下代码演示了如何为玩具示例确定众数。

正如您所看到的,“B”是输入数据中出现次数最多的值,因此是此例中的众数。

使用 Scikit-Learn 在 Python 中拟合 kNN

在处理机器学习问题时,从头开始编码算法可能更实用,尽管这对于学习来说很棒。在本节中,您将了解 kNN 方法如何在 Scikit-learn(一个完整的 Python 机器学习库之一)中实现。

从数据创建训练集和测试集以进行模型评估

您将在本节中评估您的鲍鱼 kNN 模型的有效性。在前面的部分中,您注重技术细节,但现在您的观点将更务实,更注重结果。

有其他评估模型的方法,但训练-测试分割是最常用的方法。要使用训练-测试分割来评估模型,请按如下方式将数据集分成两个部分。

  1. 模型使用训练数据进行拟合。这意味着 kNN 的邻居将从训练集中抽取。
  2. 测试数据用于评估模型。这意味着您将估计测试数据中每个鲍鱼的环数,并将结果与实际存在的环数进行比较。

您可以使用 Scikit-learn 中内置的 `train_test_split()` 函数在 Python 中将数据分割成训练集和测试集。

`test_size` 描述了您想在训练集和测试集中包含多少个观测值。如果您将 `test_size` 参数设置为 0.2,则 `test_size` 将等于原始数据的 20%,剩余的 80% 作为训练数据。

通过使用 `random_state` 参数,您可以每次执行代码时都获得相同的结果。`train_test_split()` 生成的随机数据分割使得重复结果变得困难。因此,`random_state` 经常被使用。 `random_state` 的值选择是随机的。

如上所述,您在代码中将数据分割成训练数据和测试数据。这是为了客观的模型评估所必需的。现在,您可以使用 Scikit-learn 将 kNN 模型拟合到训练集数据。

使 Scikit-Learn 回归拟合鲍鱼数据集

在 Scikit-learn 中拟合模型的第一步是创建一个适当类别的模型。您现在也必须选择超参数的值。在 kNN 方法的 Scikit-learn 实现中,您必须选择一个 k 值,称为 `n_neighbors`。为此的 Python 代码如下。

您使用 `knn_model` 创建了一个未拟合的模型。该模型将使用三个最近邻来预测未来数据点的值。要将数据加载到模型中,您可以随后在训练数据集上拟合模型。

使用 `.fit()` 函数让模型从数据中学习。`knn_model` 现在包含了生成新鲍鱼数据点预测所需的所有信息。您需要该代码在 Python 中拟合 kNN 回归。

使用 Scikit-Learn 检查模型拟合情况

但不仅仅是拟合模型就足够了。在本节中,您将查看一些可用于评估拟合度的函数。

您将使用均方根误差 (RMSE),这是回归中最常用的评估指标之一。预测的 RMSE 计算如下。

  1. 确定每个数据点的预测值和实际值之间的差异。
  2. 计算每个差值的平方。
  3. 将每个平方差相加。
  4. 确定值的平方根。

您首先可以在训练数据上评估预测误差。因此,您知道结果应该会相当好,因为您正在使用训练数据进行预测。要获得 RMSE,请使用以下代码。

  1. 确定每个数据点的预测值和实际值之间的差异。
  2. 计算每个差值的平方。
  3. 将每个平方差相加。
  4. 确定值的平方根。

您首先可以在训练数据上评估预测误差。因此,您知道结果应该会相当好,因为您正在使用训练数据进行预测。要获得 RMSE,请使用以下代码。

说明

您评估了模型仍无法访问的数据中的错误。现在 RMSE 更现实了。您可以将其解读为平均有 1.65 年的误差,因为 RMSE 衡量了预期年龄的平均误差。去看从 2.37 年到 1.65 年的改进是否是一个好改进取决于具体情况。至少您正在更接近准确地确定年龄。

到目前为止,您仅使用了 Scikit-learn kNN 方法。超参数调整和 K 的随机选择仍需完成。训练数据上的 RMSE 与测试数据上的 RMSE 差异很大。这表明模型可能泛化得更好,因为它过度拟合了训练数据集。

现在不必为此担心。在下一节中,您将学习如何使用各种调整技术来优化预测或测试误差。

绘制模型拟合图

在更新模型之前,请查看它与数据的拟合程度。您可以使用 Matplotlib 来查看您的预测是如何产生的以及模型学到了什么。

此代码块中的数组 `X_test[:,0]` 和 `X_test[:,1]` 是子集,用于生成 `X_test` 的前两列的散点图。长度和直径是前两列,您应该还记得。正如您从相关性表中看到的,它们高度相关。

您告诉 `c` 使用预期值(`test_preds`)创建颜色条。散点图中点的大小由参数 `s` 确定。使用 `cmap` 来提供 `cubehelix_palette` 颜色映射。有关使用此库进行绘图的更多信息,请参阅《使用 Matplotlib 进行 Python 制图》。

使用上面的代码,您将获得下图。

The k-nearest Neighbours (kNN) Algorithm in Python

此图中的每个点代表测试集中的一个鲍鱼,X 轴和 Y 轴显示鲍鱼的实际长度和直径。点的颜色描绘了预期的年龄。如您所见,鲍鱼的估计年龄随着长度和尺寸的增加而增加。这是一个好迹象,因为它是有道理的。它表明您的模型正在提取看起来准确的信息。

通过简单地替换用于 `c` 的变量,您可以对实际数字执行相同的分析,以确定该模式是否存在于原始数据中。

输出

此代码使用 Seaborn 生成带有颜色条的散点图。它生成下图。

The k-nearest Neighbours (kNN) Algorithm in Python

说明

这表明您的模型正在学习的趋势是有效的。

七个自变量的每种组合都可能产生一个图形。这对于本指南来说太长了,但您可以随意尝试。散点图中定义的列是唯一需要更改的内容。

这些可视化以二维方式展示了一个七维数据集。通过玩弄它们,您可以理解模型正在学习什么,以及可能它没有学习到什么或错误地学习了什么。

使用 Scikit-Learn,调优和改进 Python 中的 kNN

您的预测分数可以通过多种方式提高。虽然可以使用数据整理来改进输入数据,但 kNN 技术是本课程的主要重点。然后,您将考虑改进建模工作流的算法组成部分的方法。

使用 GridSearchCV 改进 Scikit-Learn 的 kNN 性能

到目前为止,您一直在 kNN 方法中使用 k=3,但您必须通过经验确定每个数据集的适当 k 值。

使用更少的邻居时,预测会比使用更多邻居时更加多变。

  • 如果您考虑一个邻居,预测可能会从一个地方到另一个地方发生很大变化。当您考虑您的邻里时,您的一个邻居可能与其他邻居差异很大。如果附近有异常值,您的 1-NN 预测就会出错。
  • 如果您有多个数据点,一个差异很大的邻居的影响会大大减小。
  • 如果邻居太多,每个点的预测都有可能非常接近。假设您使用所有邻居的数据进行预测。在这种情况下,每个预测都会相同。
  • 您将使用一个名为 GridSearchCV 的程序来确定哪个 k 值是理想的。此工具通常用于微调机器学习模型超参数。它将通过自动确定您数据集的理想 k 值来帮助您。

Scikit-learn 提供 GridSearchCV,其优点是使用方式与 Scikit-learn 中的模型相同。

在这里,您使用 GridSearchCV 拟合模型。本质上,GridSearchCV 会迭代地在数据的子集上拟合 kNN 回归器,并在其余子集上评估结果。重复此操作将准确估计每个 k 值对未来预测的预测能力。在此示例中,我们测试从 1 到 50 的值。

最后,它将保存表现最佳的 k 值,您可以通过 `.best_params_` 访问。

说明

此代码打印具有最低误差得分的参数。您可以从 `.best_params_` 中看到,选择 k 值为 25 将产生最佳预测性能。现在您知道了最佳值,可以观察它如何影响您的测试和训练结果。

使用此代码,您可以分析测试数据并将模型拟合到训练数据集。您可以看到,虽然测试误差比以前更好,但训练误差已得到改善。这表明您的模型并不像训练数据那样拟合。通过使用 GridSearchCV 来确定 k 值,过度拟合训练数据的担忧已大大减轻。

添加加权平均邻居,考虑距离

使用 GridSearchCV,您将测试 RMSE 从 2.37 降低到 2.17。在本部分中,您将学习如何进一步提高性能。

在这里,您将测试您的模型在使用加权平均值而不是标准平均值进行预测时是否会做得更好。这意味着距离较远的邻居对预测的影响会较小。

将 `weights` 超参数设置为“distance”值即可完成此操作。但是,设置此加权平均值可能会影响理想的 k 值。因此,GridSearchCV 将再次告知您应使用哪种类型的平均值。

在这里,您使用 GridSearchCV 来查看切换到不同的权重是否明智。与传统平均值相比,使用加权平均值后,预测误差从 2.17 降至 2.1634。即使这不是一个显著的改进,它仍然更好,因此是值得的。

使用装袋改进 Scikit-Learn 中的 kNN

您可以将装袋(bagging)作为 kNN 调优过程的第三个阶段。装袋是一种集成方法,它将一个相对简单的机器学习模型拟合到许多不同的模型上,每个模型都经过轻微修改。决策树经常用于装袋。然而,kNN 同样有效。

在性能方面,集成方法通常优于单个模型。一个模型有时可能出错,但平均而言,一百个模型出错的频率会降低。由于许多独立模型的错误被预期会平均抵消,因此预测将更加准确。

可以使用以下说明将装袋应用于您的 kNN 回归,使用 Scikit-learn。首先创建 `KNeighborsRegressor`,使用 GridSearchCV 的理想 k 和权重值。

然后,使用 `bagged_knn` 模型,使用 100 个估计器从 Scikit-learn 创建 `BaggingRegressor` 类的新实例。

使用装袋 kNN 预测的误差为 2.1616,比您之前发现的误差略低。虽然运行时间稍长,但在这种情况下是可以接受的。

结论

在了解了 kNN 算法的所有知识后,您现在就可以开始在 Python 中创建有效的预测模型了。从一个简单的 kNN 模型到一个完全优化的模型需要几个步骤,但性能提升是值得的!

在本教程中,您掌握了以下技能:理解 kNN 算法的数学基础,在 NumPy 中从头开始编程 kNN 方法,使用 Scikit-learn 实现以最少的代码拟合 kNN,并使用 GridSearchCV 确定最佳 kNN 超参数。利用装袋来提高 kNN 的性能。