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

一、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的决策边界计算

决策边界计算

导入模块

python 复制代码
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
from matplotlib import pyplot as plt

定义数据集

python 复制代码
#定义数据集
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训练

python 复制代码
knn_clf=KNeighborsClassifier(3)
knn_clf.fit(np_train_data,np_train_label)

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

python 复制代码
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的预测与绘制决策边界

python 复制代码
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()

完整代码

python 复制代码
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 个邻居,来进行分类预测。

python 复制代码
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 库中的一个函数,用于将两个或多个数组沿特定轴(通常是行或列)合并。

python 复制代码
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'。 有关选项的描述,请参阅铸造
python 复制代码
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 值。

python 复制代码
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
python 复制代码
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 返回的是原数组的视图,不会复制数据。

python 复制代码
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' 使用索引顺序。
python 复制代码
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 绘图库中的一个函数,用于绘制等高线图,显示一个二维数组的值在平面上的分布。常用于可视化函数的值在不同坐标下的变化。

python 复制代码
contour(X, Y, Z, levels=None, **kwargs)  

| 方法 | 描述 |
| X, Y | 坐标网格的矩阵,通常由 meshgrid 生成。 |
| Z | X 和 Y 有关的值矩阵,决定绘制哪条等高线 |
| levels | 可选参数,指定要绘制的等高线的高度值。如果不提供,函数会自动选择 |

kwargs 其他可选参数,用于控制线条样式、颜色、标签等,例如 colorslinestylesalpha(透明度)等
python 复制代码
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()  

相关推荐
Panesle5 分钟前
transformer架构与其它架构对比
人工智能·深度学习·transformer
幻想趾于现实7 分钟前
C# Winform 入门(2)之发送邮件
开发语言·c#
半盏茶香13 分钟前
启幕数据结构算法雅航新章,穿梭C++梦幻领域的探索之旅——堆的应用之堆排、Top-K问题
java·开发语言·数据结构·c++·python·算法·链表
我有医保我先冲30 分钟前
AI大模型与人工智能的深度融合:重构医药行业数字化转型的底层逻辑
人工智能·重构
小吴先生66634 分钟前
Groovy 规则执行器,加载到缓存
java·开发语言·缓存·groovy
秋风&萧瑟1 小时前
【QT】QT的多界面跳转以及界面之间传递参数
开发语言·qt
骑牛小道士1 小时前
JAVA- 锁机制介绍 进程锁
java·开发语言
pen-ai1 小时前
【NLP】15. NLP推理方法详解 --- 动态规划:序列标注,语法解析,共同指代
人工智能·自然语言处理·动态规划
郭涤生1 小时前
Chapter 1: Historical Context_《C++20Get the details》_notes
开发语言·c++20