Python----机器学习(KNN:决策边界,决策边界计算,交叉验证步骤)

发布于:2025-03-31 ⋅ 阅读:(15) ⋅ 点赞:(0)

一、KNN算法简介

1.1、定义

        KNN(K-Nearest Neighbor)算法是一种基于实例的学习方法,通过测量数据点之间的距离进行分类或回归分析。它是一种简单易懂的多分类技术,依赖于距离最近的邻居来推断数据点的类别或数值,为许多实际应用提供了有效的解决方案。

k-近邻算法

         邻近算法,或者说K最近邻(K-Nearest Neighbor,KNN)分类算法是数据挖掘分类技术中最简单的方法之 一,是著名的模式识别统计学方法,在机器学习分类算法中占有相当大的地位。它是一个理论上比较成 熟的方法。既是最简单的机器学习算法之一。

        所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。Cover 和Hart在1968年提出了最初的邻近算法。

        KNN是一种分类(classification)算法,它输入基于实例的学习 (instance-based learning),属于懒惰学习(lazy learning)即KNN没有显式的学习过程,也就是说 没有训练阶段,数据集事先已有了分类和特征值,待收到新样本后直接进行处理。与急切学习(eager learning)相对应。      

        KNN是一种惰性学习算法,它是基于实例的,并没有经过大量的训练来学习模型或者特征,而是仅仅记 住了需要训练的相关实例,KNN是监督学习的一种。

        KNN是给定测试实例,基于某种距离度量找出训练集中与其最靠近的k个实例点,然后基于这k个最近邻 的信息来进行预测,简言之,需要预测的实例与哪一类离得更近,就属于哪一类。

1.2、原理

        KNN算法的原理可以用“近朱者赤,近墨者黑”来概括,它是一种基于实例的学习方法,属于懒惰学习,因为没有显式的训练过程。KNN通过测量待预测样本与训练数据集中最近的K个样本之间的距离来进行分类或回归分析。

        在分类问题中,通过投票决定待预测样本的类别;

        而在回归问题中,则计算这K个样本的平均值作为最终的预测结果。

1.3、特点

        KNN算法简单易懂,易于实现;

        无需训练阶段,直接进行分类或回归;

        适用于多分类问题;

        对数据集的大小和维度不敏感。

二、决策边界

2.1、定义

        决策边界是分类算法中用于区分不同类别的虚拟边 界,即上一章节所指出的“房间”。

2.2、边界效果

        决策边界是否合理,直接影响到分类效果的好坏。

2.3、KNN与决策边界

        KNN算法通过计算待分类样本与已知样本之间的距 离,找到最近的k个样本,并根据这些样本的类别 信息进行投票,以确定待分类样本的类别。

三、KNN的决策边界计算

决策边界计算

导入模块

from sklearn.neighbors import KNeighborsClassifier
import numpy as np
from matplotlib import pyplot as plt

定义数据集

#定义数据集
point1 = [[7.7, 6.1], [3.1, 5.9], [8.6, 8.8], [9.5, 7.3], [3.9, 7.4], [5.0, 5.3], [1.0, 7.3]]
point2 = [[0.2, 2.2], [4.5, 4.1], [0.5, 1.1], [2.7, 3.0], [4.7, 0.2], [2.9, 3.3], [7.3, 7.9]]
point3 = [[9.2, 0.7], [9.2, 2.1], [7.3, 4.5], [8.9, 2.9], [9.5, 3.7], [7.7, 3.7], [9.4, 2.4]]
#特征合并
np_train_data=np.concatenate(np.array((point1,point2,point3)),axis=0)
#创建标签
np_train_label=np.array([0]*7+[1]*7+[2]*7)

构建KNN算法:实例化KNN算法,KNN训练

knn_clf=KNeighborsClassifier(3)
knn_clf.fit(np_train_data,np_train_label)

设定未知点,设定坐标点网络

x=np.linspace(0,10,100)
y=np.linspace(0,10,100)
x0,y0=np.meshgrid(x,y)
axis_xy=np.c_[x0.ravel(),y0.ravel()]

KNN的预测与绘制决策边界

y_predict=knn_clf.predict(axis_xy)
y_predit=y_predict.reshape(x0.shape)
plt.contour(x0,y0,y_predit)
plt.scatter(np_train_data[np_train_label==0,0],np_train_data[np_train_label==0,1],marker='^')
plt.scatter(np_train_data[np_train_label==1,0],np_train_data[np_train_label==1,1],marker='*')
plt.scatter(np_train_data[np_train_label==2,0],np_train_data[np_train_label==2,1],marker='s')
plt.show()

 完整代码

from sklearn.neighbors import KNeighborsClassifier  # 从 scikit-learn 导入 K 最近邻分类器  
import numpy as np  # 导入 NumPy 库以进行数组操作  
from matplotlib import pyplot as plt  # 从 matplotlib 导入 pyplot 用于绘图  

# 定义数据集  
point1 = [[7.7, 6.1], [3.1, 5.9], [8.6, 8.8], [9.5, 7.3], [3.9, 7.4], [5.0, 5.3], [1.0, 7.3]]  # 类别 0  
point2 = [[0.2, 2.2], [4.5, 4.1], [0.5, 1.1], [2.7, 3.0], [4.7, 0.2], [2.9, 3.3], [7.3, 7.9]]  # 类别 1  
point3 = [[9.2, 0.7], [9.2, 2.1], [7.3, 4.5], [8.9, 2.9], [9.5, 3.7], [7.7, 3.7], [9.4, 2.4]]  # 类别 2  

# 特征合并  
np_train_data = np.concatenate(np.array((point1, point2, point3)), axis=0)  # 将三个类别的数据组合成一个训练数据集  
# 创建标签  
np_train_label = np.array([0] * 7 + [1] * 7 + [2] * 7)  # 创建对应每个数据点的标签  

# 构建 KNN 算法,实例化,KNN 训练  
knn_clf = KNeighborsClassifier(3)  # 创建 KNN 分类器,k=1 表示考虑最近的一个邻居  
knn_clf.fit(np_train_data, np_train_label)  # 使用训练数据和标签来训练 KNN 模型  

# 定义未知点坐标网格  
x = np.linspace(0, 10, 100)  # 创建 x 坐标的线性空间,从 0 到 10,包含 100 个点  
y = np.linspace(0, 10, 100)  # 创建 y 坐标的线性空间,从 0 到 10,包含 100 个点  
x0, y0 = np.meshgrid(x, y)  # 创建二维网格坐标  
axis_xy = np.c_[x0.ravel(), y0.ravel()]  # 将网格坐标展平,以便于预测  

# KNN 的预测绘制决策边界  
y_predict = knn_clf.predict(axis_xy)  # 对所有未知点进行分类预测  
y_predit = y_predict.reshape(x0.shape)  # 将预测结果按原网格形状排列  

# 绘制决策边界  
plt.contour(x0, y0, y_predit)  # 绘制决策边界  
plt.scatter(np_train_data[np_train_label == 0, 0], np_train_data[np_train_label == 0, 1], marker='^')  # 绘制类别 0 的点  
plt.scatter(np_train_data[np_train_label == 1, 0], np_train_data[np_train_label == 1, 1], marker='*')  # 绘制类别 1 的点  
plt.scatter(np_train_data[np_train_label == 2, 0], np_train_data[np_train_label == 2, 1], marker='s')  # 绘制类别 2 的点  
plt.show()  # 显示绘图结果  

K值选择

        在KNN中,需要人为选择不同的K的不同取值,这 个参数是需要人为选择的。需要人为确定的参数称 为超参数(hyperparameter)。

选择太小:

        优点:复杂的数据集,K值较小可能会提供更详细 的决策边界,因为模型更加灵活。

         缺点:容易受到局部结构的影响,模型对噪声和异 常值的影响更大。

 选择太大:

        优点:考虑了更多的全局信息,对于平滑的数据集, 较大的K值可以提供更稳定的决策边界。

        缺点:对于复杂的数据集,较大的K值可能会导致 模型过于简单,无法准确捕获数据的局部特征。 

四、交叉验证

步骤

        1、准备数据集:

                准备好包含特征和标签的 数据集。

        2、K折交叉验证:

                确定K的值,例如选择5或7 作为K值。

        3、划分数据集:

                将数据集划分为K个大小相似的子集

        4、循环训练和评估:

                使用K-1个子集作为训练集, 剩余的1个子集作为测试集。 在训练集上训练KNN模型。 使用训练好的模型对测试集进 行预测。 使用性能指标评估。

        5、计算平均性能:

                将K次验证的性能指标取 平均值,作为KNN模型的 最终性能评估。

        6、选择最佳K值:

                可以尝试不同的K值,并 通过交叉验证选择性能最 好的K值。然后选择在交 叉验证中表现最佳的K值。

        7、选定最终K值:

                使用选择的最佳K值,在整 个训练集上重新训练KNN 模型,以获得最终的模型。

五、库函数 

5.1、KNeighborsClassifier()

        是 scikit-learn 库中的一个分类模型实现,属于 K 最近邻(KNN)算法。该模型通过计算输入数据点与训练数据集中每个点的距离,找出最近的 K 个邻居,来进行分类预测。

class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, *, weights='uniform', algorithm='auto', leaf_size=30, p=2, metric='minkowski', metric_params=None, n_jobs=None)
方法 描述
n_neighbors

默认值 = 5

默认情况下用于查询的邻居数。

weights

预测中使用的权重函数。可能的值:

  • 'uniform' :均匀的权重。每个邻域中的所有点 的权重相等。

  • 'distance' :按距离的倒数对点进行加权。 在这种情况下,查询点的近邻将具有 比距离较远的邻居有更大的影响力。

  • [callable] :一个用户定义的函数,它接受 距离数组,并返回相同形状的数组 包含权重。

algorithm

用于计算最近邻的算法:

  • 'ball_tree' 将使用

  • 'kd_tree' 将使用

  • 'brute' 将使用暴力搜索。

  • 'auto' 将尝试决定最合适的算法 基于传递给 method 的值。

注意:拟合稀疏输入将覆盖 this 参数,使用蛮力。

leaf_size 传递给 BallTree 或 KDTree 的叶大小。这可能会影响 构造和查询的速度以及内存 需要来存储树。最佳值取决于 问题的性质。
p Minkowski 度量的 Power 参数。当 p = 1 时,这是等效的 使用 manhattan_distance (L1) 和 euclidean_distance (L2) 表示 p = 2。 对于任意 p,使用 minkowski_distance (l_p)。此参数是预期的 要积极。
metric

用于距离计算的公制。默认值为 “minkowski”,它 当 p = 2 时,得到标准欧几里得距离。请参阅 scipy.spatial.distance 和 Valid metric 中列出的量度 值。

如果度量是“预先计算的”,则假定 X 是一个距离矩阵,并且 拟合时必须为方形。X 可以是稀疏图,其中 只有 “nonzero” 元素才能被视为邻居。

如果 metric 是一个可调用函数,它需要两个表示 1D 的数组 vectors 作为输入,并且必须返回一个表示距离 在这些向量之间。这适用于 Scipy 的指标,但效果较弱 效率高于将指标名称作为字符串传递。

metric_params metric 函数的其他关键字参数。
n_jobs 要为邻居搜索运行的并行作业数。 表示 1,除非在上下文中。 表示使用所有处理器。有关更多详细信息,请参阅 术语表 。 不影响 method。None-1

5.2、concatenate()

        是 NumPy 库中的一个函数,用于将两个或多个数组沿特定轴(通常是行或列)合并。

numpy.concatenate((a1, a2, ...), axis=0, out=None, dtype=None, casting="same_kind")
方法 描述
a1, a2, … 数组必须具有相同的形状,但维度 对应于 axis (默认情况下是第一个)。
axis 数组将沿其连接的轴。如果 axis 为 None,则 数组在使用前被展平。默认值为 0。
out 如果提供,则为放置结果的目标。形状必须为 correct,匹配 concatenate 在 no out 参数。
dtype 如果提供,目标数组将具有此 dtype。不能 与 out 一起提供。
casting 控制可能发生的数据类型转换。默认为 'same_kind'。 有关选项的描述,请参阅铸造
import numpy as np  

array1 = np.array([[1, 2], [3, 4]])  
array2 = np.array([[5, 6], [7, 8]])  
result = np.concatenate((array1, array2), axis=0)  # 沿行合并  
# result: [[1, 2], [3, 4], [5, 6], [7, 8]]  

5.3、meshgrid()

        是 NumPy 函数,用于生成二维网格坐标,通常用于函数绘图或参数化曲面绘图。meshgrid 接受两个一维数组(通常为 x 和 y 轴的坐标),并返回两个矩阵,分别表示每个坐标点的 x 和 y 值。

numpy.meshgrid(*xi, copy=True, sparse=False, indexing='xy')
方法 描述
x1, x2,…, xn 表示网格坐标的 1-D 数组。
indexing 输出的笛卡尔 ('xy', default) 或矩阵 ('ij') 索引。 有关更多详细信息,请参阅 Notes。
sparse

如果为 True,则返回的维度 i 坐标数组的形状将从 减少到 。这些稀疏坐标格网是 旨在与 Broadcasting 一起使用。当所有 坐标,则广播仍然会导致 全尺寸结果数组。(N1, ..., Ni, ... Nn)(1, ..., 1, Ni, 1, ..., 1)

默认值为 False。

copy 如果为 False,则返回原始数组的视图,以便 节省内存。默认值为 True。请注意,可能会返回非连续的 阵 列。此外,广播数组的多个元素 可能是指单个内存位置。如果需要写入 数组中,请先制作副本。sparse=False, copy=False
import numpy as np  

x = np.linspace(0, 5, 5)  # x 轴的线性空间  
y = np.linspace(0, 5, 5)  # y 轴的线性空间  
X, Y = np.meshgrid(x, y)  # 生成网格坐标  
# X, Y: 网格中的每个点的坐标  
'''
(array([[0.  , 1.25, 2.5 , 3.75, 5.  ],
        [0.  , 1.25, 2.5 , 3.75, 5.  ],
        [0.  , 1.25, 2.5 , 3.75, 5.  ],
        [0.  , 1.25, 2.5 , 3.75, 5.  ],
        [0.  , 1.25, 2.5 , 3.75, 5.  ]]),
 array([[0.  , 0.  , 0.  , 0.  , 0.  ],
        [1.25, 1.25, 1.25, 1.25, 1.25],
        [2.5 , 2.5 , 2.5 , 2.5 , 2.5 ],
        [3.75, 3.75, 3.75, 3.75, 3.75],
        [5.  , 5.  , 5.  , 5.  , 5.  ]]))
'''

5.4、ravel()

        是 NumPy 的一个方法,用于将多维数组展平为一维数组。它返回一个连续的一维数组,表示原数组中的所有元素。与 flatten 方法不同的是,ravel 返回的是原数组的视图,不会复制数据。

numpy.ravel(a, order='C')
方法 描述
a Input 数组。a 中的元素按照 order 指定的顺序读取,并打包为 1-D 数组。
order 使用此索引顺序读取 a 的元素。“C” 表示 以行优先、C 样式顺序为元素编制索引, 最后一个轴索引变化最快,返回到第一个 轴索引变化最慢。'F' 表示为元素编制索引 以 column-major、Fortran 样式的顺序,使用 第一个索引更改最快,最后一个索引更改 慢。请注意,'C' 和 'F' 选项不考虑 底层数组的内存布局,并且仅引用 轴索引的顺序。“A” 表示读取 如果 a 是 Fortran 连续的,则为类似 Fortran 的索引顺序 memory,否则类似 C 的顺序。'K' 表示读取 元素(按它们在内存中出现的顺序排列),但 当步幅为负数时反转数据。默认情况下,'C' 使用索引顺序。
import numpy as np  

array = np.array([[1, 2, 3], [4, 5, 6]])  
flattened = array.ravel()  # 将二维数组展平为一维  
# flattened: [1, 2, 3, 4, 5, 6]  

5.5、contour()

        是 Matplotlib 绘图库中的一个函数,用于绘制等高线图,显示一个二维数组的值在平面上的分布。常用于可视化函数的值在不同坐标下的变化。

contour(X, Y, Z, levels=None, **kwargs)  
方法 描述
X, Y 坐标网格的矩阵,通常由 meshgrid 生成。
Z  X 和 Y 有关的值矩阵,决定绘制哪条等高线
levels 可选参数,指定要绘制的等高线的高度值。如果不提供,函数会自动选择
kwargs 其他可选参数,用于控制线条样式、颜色、标签等,例如 colorslinestylesalpha(透明度)等
import matplotlib.pyplot as plt  
import numpy as np  

x = np.linspace(-3.0, 3.0, 100)  
y = np.linspace(-3.0, 3.0, 100)  
X, Y = np.meshgrid(x, y)  
Z = np.sin(np.sqrt(X**2 + Y**2))  # 计算 Z 值  

plt.contour(X, Y, Z)  # 绘制等高线  
plt.colorbar()  # 添加色条  
plt.show()  

 

 


网站公告

今日签到

点亮在社区的每一天
去签到