python学智能算法(七)|KNN邻近算法

news2025/3/12 16:33:09

【1】引言

前述学习进程中,已经了解了一些非常经典的智能算法,相关文章包括且不限于:

python学智能算法(三)|模拟退火算法:深层分析_模拟退火 动画演示-CSDN博客

python学智能算法(四)|遗传算法:原理认识和极大值分析_遗传算法和模拟退火时间复杂度-CSDN博客

python学智能算法(五)|差分进化算法:原理认识和极小值分析-CSDN博客

python学智能算法(六)|神经网络算法:BP神经网络算法入门-CSDN博客

这些算法一定程度上都非常关注自变量和因变量的内在关系,今天换一个方向,不区分自变量因变量,或者就只有因变量。因为只有一个,叫它变量也能完整描述。现在的主要关注点是:变量和变量之间的位置关系。按这种关注方式运行的智能算法,就是KNN算法。

【2】原理解释

如果一个样本在特征空间中的K个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。

除了看CSDN的博文,也可以到以下网址学习:

第2章 k-近邻算法 - 《机器学习实战(Machine Learning in Action)》 - 书栈网 · BookStack

What is k-Nearest Neighbor (kNN)? | A Comprehensive k-Nearest Neighbor Guide | Elastic

以及未来会反复用到的scikit-learn的官网学习:

KNNImputer — scikit-learn 1.6.1 documentation

【3】代码测试

理解一个算法的最简单途径就是用代码跑一次。

【3.1】准备工作

首先引入必要模块:

import numpy as np #引入numpy模块
import matplotlib.pyplot as plt #引入matplotlib模块
from sklearn.datasets import load_iris #引入sklearn模块

这里和以前不同的是,在数字处理模块numpy和画图模块matplotlib之外,新增加了一个sklearn模块。

sklearn模块是一个免费的数据库,里面存储了可以公开使用的数据。

学习sklearn模块就直接去官网:Examples — scikit-learn 1.6.1 documentationr

为了实现对sklearn模块中数据的调用,还需要处理一下:

# 加载鸢尾花数据集
# 从免费的sklearn库中存储的鸢(yuān)尾花数据集
iris = load_iris()
# X存储了iris的特征数据
# X的形状是(150行,4列)的矩阵数组
# 意味着有 150 个样本,每个样本有 4 个特征,分别是花萼长度、花萼宽度、花瓣长度和花瓣宽度
# 这些特征是用于描述每个鸢尾花样本的属性,是模型进行学习和预测的依据
X = iris.data  # 特征数据
# y中存储了150个数,相当于150个标签
y = iris.target  # 标签数据

 X取到的鸢尾花统计数据是固定的150行4列矩阵;4列代表了四个详细特征,可以理解为每一种鸢尾花样本都有4个特征,150行数据代表150种鸢尾花样本,y的值就是150。

【3.2】主函数

为了实现对整体算法的掌握,推荐的方式是先读主函数,然后再去读子函数。主函数会告知算法会调用哪些子函数,通过对主函数结构的阅读,会理解整个算法的原理。

# 设置 k 值
k = 5
# 进行预测
y_pred = knn_predict(X_train, y_train, X_test, k)

主函数先设置了k=5,代表取最邻近的5个样本量一起归类,然后预测数据y_pred直接调用了子函数knn_predict()。

【3.3】子函数

【3.3.1】knn_predict()

在主函数的指引下,直奔子函数knn_predict():

# 定义 KNN 分类器
def knn_predict(X_train, y_train, X_test, k):
    y_pred = []
    for test_sample in X_test:
        # 计算测试样本与所有训练样本的欧氏距离
        # test_sample 是一个一维数组(形状为 (n_features,))从数学上看是一个一行n_features的行向量
        # X_train 是一个(形状为 (n_train_samples, n_features))数组,从数学上看X_train的每一行也是一个一行n_features的行向量
        # X_train的每一行都会和test_sample作差,作差过程是同一位置元素相减
        # X_train 是一个(形状为 (n_train_samples, n_features))数组,所以会有n_train_samples行计算结果
        # 作差得到的数组形状为 (n_train_samples, n_features)
        # axis=1的意思是,在作差得到的数组内,每一个行内部求和,一共会得到n_train_samples行1列的数据
        distances = np.sqrt(np.sum((X_train - test_sample) ** 2, axis=1))
        # 获取距离最近的 k 个样本的索引
        # np.argsort会对distances进行从小到大的排序,但是排序后输出的数据原来对应的位置索引
        # 由于数据从小到大排序,输出的位置索引成为了输出矩阵数据,这时候对输出矩阵取出前k个
        # k_indices就是获得最小距离中的前k个距离对应的位置索引
        k_indices = np.argsort(distances)[:k]
        # 获取这 k 个样本的标签
        # 将k_indices 带回y_train,用位置索引的形式,找出距离test_sample最近的k行数据
        k_nearest_labels = y_train[k_indices]
        # 统计每个标签出现的次数
        # k_nearest_labels中的所有数据会被逐一统计归类
        # 输出unique_labels代表一共有unique_labels个不同的数据,每个数据出现的次数为counts
        unique_labels, counts = np.unique(k_nearest_labels, return_counts=True)
        # 选择出现次数最多的标签作为预测结果
        predicted_label = unique_labels[np.argmax(counts)]
        # y_pred是个空矩阵,往里面叠加出现次数最多的标签
        y_pred.append(predicted_label)
    return np.array(y_pred)

首先会看到除了定义一个空列表y_pred=[],剩下的是一个大的for循环。

在for循环里面:

第一步,x_train-test_sample作差后平方求和,作差过程是同一位置相减,求和是按照行的形式,把一行内部的所有列加在一起,所以最后会获得和x_train行数一样多的一个单列数组,这个数组还要再开方一次才会赋值给distance。distance是按照数学里面欧几里得距离求解的公式定义的。

第二步,调用np.argsort()函数对所有的distance元素从小到大排个序,这里通过索引的形式调用了k,意思是只选用前k个元素,也就是距离最近的k个元素。但此时输出的是前k个元素的位置索引k_indices。

第三步,通过k_indices,可以直接访问到y_train,因为x_train和y_train在行数上其实一一对应。此时获得的最近的k个元素都存储在k_nearest_labels中。

第四步,调用np.unique()函数,对存储最近的k个元素k_nearest_labels进行分类,因为k个元素可能有一些是相等的,所以会合并一些相等元素,获得独特的unique_labels和具体的数量counts。

第五步,在所有counts中,调用np.argmax()函数分析出最大的counts,找出这个counts对应的具体unique_lables赋值给predicted_lablel。这个predicted_lablel指向次轮距离计算中k个最近值出现频次最高的元素。

第六步,将predicted_lablel存储进y_pred列表。

重复上述六步,直至所有的x_train都通过计算。

虽然在这个函数里可以很直白理解knn运算过程,但几个参数的来源还需进一步追溯来加深理解。这就需要学习train_test_split()函数。

【3.3.2】train_test_split()
# 划分数据集为训练集和测试集
def train_test_split(X, y, test_size=0.3, random_state=42):
    # 设置随机数的种子目的是保证每次生成的随机数一致
    np.random.seed(random_state)
    # len(X)=150
    # indices是[0,len(X)-1]中的每一个整数组成的数组
    indices = np.arange(len(X))
    # 调用np.random.shuffle()函数将indices顺序随机打乱
    np.random.shuffle(indices)
    # test_size在函数的输入参数中提前给出,此处和len(X)相乘后取整
    # test_size在经int()函数取正时,采用的是向下1取正方式
    # test_size本身要比indices小
    test_size = int(len(X) * test_size)
    # test_indices按照索引的形式,只取出indices数组中索引位置从0到test_size-1的部分
    test_indices = indices[:test_size]
    # train_indices按照索引的形式,取出indices数组中索引位置从test_size开始到末尾所有的数据
    train_indices = indices[test_size:]
    # X_train按照索引的形式,取出X数组中train_indices所包含数据对应的行数
    # train_indices是indices数组中索引位置从test_size开始到末尾所有的数据
    # X_train取出X数组中行数=【从test_size开始到末尾所有的数据】的行
    X_train = X[train_indices]
    # y_train按照索引的形式,取出y数组中train_indices所包含数据对应的行数
    # train_indices是indices数组中索引位置从test_size开始到末尾所有的数据
    # y_train取出X数组中行数=【从test_size开始到末尾所有的数据】的行
    y_train = y[train_indices]
    # X_test按照索引的形式,取出X数组中test_indices所包含数据对应的行数
    # test_indices是indices数组中索引位置从0到test_size所有的数据
    # X_train取出X数组中行数=【从0到test_size所有的数据】的行
    X_test = X[test_indices]
    # y_test按照索引的形式,取出y数组中test_indices所包含数据对应的行数
    # test_indices是indices数组中索引位置从0到test_size所有的数据
    # y_test取出X数组中行数=【从0到test_size所有的数据】的行
    y_test = y[test_indices]
    return X_train, X_test, y_train, y_test

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

train_test_split()函数直接读取了X,y,还增加了参数test_size=0.3以及random_state=42。test_size是用来划定X和y的测试集大小;random_state=42则是在机器学习中随机数种子的一个习惯性定义,传说和电影有关,大家其实可以随意改动这个数字。

在生成随机数之后,用indices直接取得了X的所有行数索引。

然后调用np.random.shuffle()函数对indices进行了随机换序,这样做的目的其实是让用于训练的数据集对整体样本量具有代表性。

之后定义的test_size调用了test_size=0.3来设定一个较小的位置索引范围,test_indices则提取了前test_size行数据。由于之前已经打乱了indices的顺序,所以前test_size行数据对整体样本量具有代表性。

剩余的数据则由train_indices存储。

具体的:

X_test存储了X的前test_size行数据;

y_test存储了y的前test_size行数据;

X_train存储了X的从第test_size行开始到结束的所有数据;

y_train存储了y的从第test_size行开始到结束的所有数据。

train_test_split()将X和y分解为测试部分和训练部分。

【3.4】预测

在主函数的运行过程中,因为x_test是参考位置点,所以经过计算获得的训练数据y_pred数量和x_test一样多,自然也和y_test一样多。

所以,直接调用np.mean()函数计算y_pred == y_test,就可以获得计算的准确率。

【3.5】可视化

在预测部分,实际上所有计算过程已经结束。运行代码在控制台也会获得输出:

NN 模型的准确率: 1.00

可见KNN算法准确识别出了鸢尾花的类型。

为了进一步图片展示,选取了鸢尾花的两个特征来画散点图,实际上这话总选择是随机的,只要选择两个特征可以画散点图即可。同一类别是根据欧氏距离来的,所以用欧氏距离来控制颜色,就可以获得鸢尾花的分类效果:

# 可视化预测结果(这里只选取前两个特征进行可视化)
plt.figure(figsize=(10, 6))
plt.scatter(X_test[:, 0], X_test[:, 1], c=y_pred, cmap='viridis', edgecolor='k', s=50)
plt.title('KNN Classification Results')
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.show()

运行代码获得的图像为:

图1 KNN运行效果

【4】细节说明

tes-size和k都是随机定义的数据,可以自由修改测试KNN算法运行效果。

【5】总结

学习了KNN算法的基本原理,使用python通过KNN算法实现了对鸢尾花的分类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2313840.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java数据结构第二十二期:Map与Set的高效应用之道(一)

专栏:Java数据结构秘籍 个人主页:手握风云 目录 一、Map和Set 1.1. 概念 二、搜索树 2.1. 概念 2.2. 查找操作 2.2. 插入操作 2.3. 删除操作 2.4. 性能分析 三、搜索 3.1. 概念及场景 3.2. 模型 四、Map 4.1. Map的说明 3.2. Map的使用 五…

兴达易控modbusTCP转profinet接防撞雷达测试

modbusTCP转profinet接防撞雷达测试 随着工业自动化程度的不断提高,现场设备之间的通信需求日益增长。ModbusTCP作为一种广泛应用的工业通信协议,因其简单、可靠的特点,被广泛应用于各种自动化设备中。而Profinet作为工业以太网的一种&#…

flutter实践:断点调试踩坑

问题:使用VSCode开发flutter,最近突然开始打断点不生效,程序可以attach,修改有日志输出,但是断点处怎么都停不了,程序异常断点会停。 分析:开始误以为是flutterSDK出了问题折腾了一天,后来又怀疑是lauch.j…

STM32——GPIO介绍

GPIO(General-Purpose IO ports,通用输入/输出接口)模块是STM32的外设接口的核心部分,用于感知外界信号(输入模式)和控制外部设备(输出模式),支持多种工作模式和配置选项。 1、GPIO 基本结构 STM32F407 的每个 GPIO 引脚均可独立配置,主要特性包括: 9 组 GPIO 端口…

Photo Works在线图片编辑器:一键修复老照片,轻松焕新记忆

★【概况介绍】 今天突然收到我的朋友电脑出故障了,截图给我,我一看就知道这个是缺少必要的组件引起的故障。结合这个问题,我来谈谈自己的解决思路和方法,希望能够帮助到大家。帮助大家是我最开心的事情。以前只是帮朋友解决问题,没有记录下来,刚刚接触到这个平台,刚好可…

SQLiteStudio:一款免费开源跨平台的SQLite管理工具

目录 1.简介 2.下载与安装 3.实现分析 4.总结 1.简介 SQLiteStudio 是一款专门用于管理 SQLite 数据库的图形化工具,由波兰开发者开发并维护。由于 SQLite 以其轻量级、零配置、嵌入式等特性被广泛应用于各种小型项目、移动应用和桌面应用中,而 SQLi…

Markdown 语法入门指南(VSCode 版)

此博客为一份详细的 Markdown 语法入门指南,专门针对在 VSCode 上使用 Markdown 的零基础用户。这份指南将包括 Markdown 的基础语法、在 VSCode 中的安装与使用方式、常见问题及注意事项。 Markdown 是一种轻量级标记语言,使用纯文本符号来标记格式&am…

PostgreSQL学习笔记:PostgreSQL vs MySQL

PostgreSQL 和 MySQL 都是广泛使用的关系型数据库管理系统,它们有以下一些对比: 一、功能特性 1. 数据类型支持 PostgreSQL:支持丰富的数据类型,包括数组、JSON、JSONB、范围类型、几何类型等。对于复杂数据结构的存储和处理非…

内存检测工具——Qt Creator

前言 检测内存错误的工具,有很多个,我今天粗浅的学了一下可在Qt上使用的工具们: Dr.Memory 工具之前我曾在关注的博主上看到相关的博客:C(Qt)软件调试---内存调试器Dr.Memory(21)_dr. memory-CSDN博客 今…

2.4 基于Vitest的单元测试基础设施搭建

文章目录 1. 现代单元测试体系解析测试金字塔演进Vitest核心定位2. 基础设施架构设计整体架构图3. 环境配置全流程3.1 基础环境搭建3.2 配置文件`vitest.config.ts`3.3 测试环境初始化4. 测试用例编写规范4.1 基础测试示例4.2 Vue组件测试4.3 异步逻辑测试5. Mock策略深度优化5…

⭐算法OJ⭐链表排序【归并排序】(C++/JavaScript 实现)

文章目录 148. Sort List解题思路归并排序的基本思想归并排序的步骤 实现实现步骤C 实现JavaScript 实现 复杂度总结 148. Sort List Given the head of a linked list, return the list after sorting it in ascending order. 解题思路 链表排序问题可以通过多种方法解决&am…

SegMAN模型详解及代码复现

SegMAN模型概述 模型背景 在深入探讨SegMAN模型之前,我们需要了解其研究背景。在SegMAN出现之前,计算机视觉领域的研究主要集中在以下几个方面: 手工制作方法,如SIFT基于卷积神经网络(CNN)的方法,如STN和PTN对平移、…

Manus AI:多语言手写识别的技术革命与未来图景

摘要:在全球化浪潮下,跨语言沟通的需求日益迫切,但手写文字的多样性却成为技术突破的难点。Manus AI凭借其多语言手写识别技术,将潦草笔迹转化为精准数字文本,覆盖全球超百种语言。本文从技术原理、应用场景、行业价值…

Stable Diffusion游戏底模推荐

一、基础通用型底模 SDXLbase 📚 官方原版底模,支持1024x1024高清出图,适用于各类游戏场景和角色的基础生成,建议作为微调训练的基准模型。 来源: 相关搜索结果 写实风格搭配推荐 🎨 搭配 9realisticSDXL 或 麻袋real…

理解字符流和字节流,节点流和处理流、缓冲流、InputStreamReader、BufferInputStream、BufferReader...

DAY10.2 Java核心基础 IO流 字符流和字节流 字符流和字节流在每次处理数据的单位不同,一个是字符,一个是字节 如果复制文件类型是文本类型,字节流字符流都可以 如果复制的文件类型是非文本类型,则只能使用字节流,使…

DBeaver安装教程+连接TDengine数据库

为TDengine安装的DBeaver教程 安装 23.1.1 版本以上的DBeaver 因为官方文档说这个版本之上的DBeaver才支持TDengine内嵌前往DBeaver 官方文档进行版本下载滑到链接最下面点击进入 点击download,进入选择下载版本 等待下载成功即可双击自行安装 打开数据库连接TDen…

【三维重建】Proc-GS:使用3DGS的程序性城市建筑生成

标题:《Proc-GS: Procedural Building Generation for City Assembly with 3D Gaussians》 项目:https://city-super.github.io/procgs/ 来源:香港中文大学;上海人工智能实验室 等 文章目录 摘要一、 程序代码定义 (Procedural Co…

商业智能BI的未来,如何看待AI+BI这种模式?

昨天在和一位朋友线上聊天的时候,提了一个问题,你是如何看待AI(人工智能)BI(商业智能)这种模式和方向的,我大概来说一下我个人的看法。 以我在商业智能BI项目中接触到的行业和企业,…

25.3.12.Linux内核如何和设备树协同工作的?

1.编写设备树 cd arch/riscv/boot/dts/ 再cd到厂商,例如下述内容。 2.编译设备树(dts->dtb)通过dtc命令来转换 3.解析设备树 例如上述内容,都是对设备树的解析。 这里重点说一下内核对设备树的处理吧,因为这个内容是设备树的重点了。 从源代码文件 dts 文件开始

Flutter 基础组件 Text 详解

目录 1. 引言 2. 基本使用 3. 自定义样式 4. 文本对齐与溢出控制 5. 外边距 5.1 使用 Container 包裹 5.2 使用 Padding 组件 5.3 在 Row/Column 中使用 5.4 动态边距调整 5.5 关键区别说明 5.6 设置 margin 无效 6. 结论 相关推荐 1. 引言 Text 组件是 Flutter 中…