k近邻算法K-Nearest Neighbors(KNN)
算法核心
KNN算法的核心思想是“近朱者赤,近墨者黑”。对于一个待分类或预测的样本点,它会查找训练集中与其距离最近的K个样本点(即“最近邻”)。然后根据这K个最近邻的标签信息来对当前样本进行分类或回归。 在分类任务中,通常是根据K个最近邻中出现次数最多的类别来确定待分类样本的类别;在回归任务中,则是根据K个最近邻的目标值的平均值来预测待预测样本的目标值。

例如在图中:
如果我们以k=3画圆,因为在圆圈内ClassB出现的数量要比ClassA更多,因此我们可以把它归到ClassB
但如果我们以k=6画圆,因为在圆圈内ClassA出现的数量要比ClassB更多,因此我们可以把它归到ClassA
值得注意的是:这里的k是离我们观测点最近的第k个点,而非半径
距离选择
这里的距离可以采用不同的求法,常见的距离度量方式有:
• 欧氏距离:这是最常见的距离度量方式,它计算的是样本点在多维空间中的直线距离。对于两个样本点 x = (x_1, x_2, ..., x_n) 和 y = (y_1, y_2, ..., y_n) ,欧氏距离定义为 \sqrt{(x_1 - y_1)^2 + (x_2 - y_2)^2 + ... + (x_n - y_n)^2} 。• 曼哈顿距离:它计算的是样本点在坐标轴方向上的绝对距离之和,即 |x_1 - y_1| + |x_2 - y_2| + ... + |x_n - y_n| 。在某些场景下,比如在城市街区网格中计算两点之间的距离时,曼哈顿距离更符合实际情况。
• 明可夫斯基距离:它是一种更通用的距离度量,欧氏距离和曼哈顿距离都是它的特例。明可夫斯基距离的定义为

当 p = 2 时,就是欧氏距离;当 p = 1 时,就是曼哈顿距离
K值的选择
K值的选择对KNN算法的性能影响很大。 如果K值选得太小,算法会过于敏感,容易受到噪声数据的影响。例如,当K = 1时,一个噪声点可能会直接影响到分类或回归的结果。如果K值选得太大,算法又会过于“平滑”,可能会将不同类别的样本混合在一起。比如在一个复杂的分类问题中,如果K值过大,可能会导致不同类别之间的边界模糊。 通常,k值选择时一般选择的是比较小的值,像是3、5、7、9这样的个位单数
kd树优化算法
kd树(k-d tree,k维树)是用于优化KNN算法中最近邻搜索过程的一种数据结构。
kd树的作用
1. 加速最近邻搜索
• 在KNN算法中,最耗时的部分是计算待预测点与训练集中所有点之间的距离,以找到最近的K个邻居。当训练集规模很大时,这种暴力搜索方法效率非常低。
• kd树通过将训练数据组织成一种树形结构,能够快速定位到与目标点最近的区域,从而减少需要计算距离的点的数量,大大加快最近邻搜索的速度。
2. 空间划分
• kd树是一种二叉树结构,它通过递归地将数据空间划分为超矩形区域。在每次划分时,选择一个维度(通常是方差最大的维度)作为划分轴,将数据点按照该维度的中值分为两部分,分别存储在树的左子树和右子树中。通过这种方式,kd树将整个数据空间划分为多个小区域,每个区域对应树中的一个节点。
kd树的构建过程
1. 选择划分维度
• 在构建kd树时,需要选择一个维度作为划分轴。通常会选择方差最大的维度,因为方差大的维度意味着数据在这个方向上的分布更分散,划分效果更好。
2. 选择划分点
• 在选定的维度上,选择该维度的中值作为划分点。将小于中值的点分配到左子树,大于中值的点分配到右子树。
3. 递归划分
• 对左右子树重复上述过程,每次选择不同的维度进行划分,直到每个区域只包含一个数据点,或者满足其他停止条件。
kd树在KNN中的使用
1. 搜索最近邻
• 当需要找到某个目标点的最近邻时,kd树会从根节点开始,沿着树的结构向下搜索。根据目标点在当前划分维度上的值,决定是进入左子树还是右子树。通过这种方式,可以快速定位到目标点所在的区域。
2. 回溯查找
• 单纯沿着树向下搜索可能无法找到真正的最近邻,因为可能存在其他区域的点距离目标点更近。因此,在搜索到叶子节点后,需要进行回溯。在回溯过程中,检查每个节点的划分超平面与目标点的距离,如果这个距离小于当前已知的最近距离,就需要检查另一侧子树,以确保找到真正的最近邻。
示例场景
假设我们有一个二维空间中的数据点集合,目标是找到某个目标点\(P\)的最近邻点。我们将通过以下步骤来展示如何利用空间划分和距离关系来优化搜索过程。
1.数据点和目标点
假设我们有以下数据点:
• \(A(1,1)\)
• \(B(2,2)\)
• \(C(10,10)\)
• \(D(11,11)\)
• \(E(12,12)\)
目标点\(P\)的坐标为\((0,0)\)。
2.构建空间划分结构(如kd树)
为了优化搜索过程,我们首先构建一个kd树。假设我们按照以下步骤构建kd树:
1. 选择第一个维度(x轴)作为划分轴,找到中值点\(B(2,2)\)。
2. 将数据点分为两部分:
• 左子树:\(A(1,1)\)
• 右子树:\(C(10,10)\),\(D(11,11)\),\(E(12,12)\)
3. 对右子树,选择第二个维度(y轴)作为划分轴,找到中值点\(D(11,11)\)。
4. 继续划分,直到每个区域只包含一个点。
构建的kd树如下:
B(2, 2)/ \A(1, 1) D(11, 11)/ \C(10, 10) E(12, 12)
3.利用距离关系跳过某些点
现在,我们从目标点\(P(0,0)\)开始搜索其最近邻点。
第一步:从根节点开始
• 从根节点\(B(2,2)\)开始,计算\(P\)与\(B\)的距离:

第二步:选择子树
• 由于\(P\)的 x 坐标小于\(B\)的 x 坐标,我们进入左子树,到达点\(A(1,1)\)。
• 计算\(P\)与\(A\)的距离:

• 目前,\(A\)是最近邻点,最近距离为\(\sqrt{2}\)。
第三步:回溯并跳过某些点
• 回溯到根节点\(B\)。检查右子树是否可能包含更近的点。
• 计算目标点\(P\)到右子树划分超平面(x=2)的距离:

• 由于\(2>\sqrt{2}\),这意味着右子树中任何点到\(P\)的距离都不会小于当前的最近距离\(\sqrt{2}\)。因此,我们可以跳过右子树中的所有点(\(C\),\(D\),\(E\)),而不需要进一步计算它们与\(P\)的距离。
4.优化后的搜索过程
通过上述步骤,我们利用了空间划分(kd树)和距离关系(跳过距离远的点)来优化搜索过程。最终,我们确定\(A(1,1)\)是目标点\(P(0,0)\)的最近邻点,而无需计算\(P\)与右子树中所有点的距离。
5.复杂度分析
• 暴力搜索:计算目标点与所有点的距离,复杂度为\(O(DN)\)。
• 优化后的搜索:通过kd树的空间划分和跳过无关区域,复杂度降低到\(O(DN\log N)\)。这是因为:
• 构建kd树的复杂度为\(O(N\log N)\)。
• 搜索过程通过递归和回溯,每次只需要检查部分点,而不是所有点。
应用实例
以下是一个使用Python和`scikit-learn`库实现的KNN算法对鸢尾花(Iris)数据集进行分类的完整代码示例。鸢尾花数据集是机器学习中常用的入门数据集,包含150个样本,每个样本有4个特征(花萼长度、花萼宽度、花瓣长度、花瓣宽度),分为3个类别。
# 导入必要的库
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score# 加载鸢尾花数据集
iris = load_iris()
X = iris.data # 特征数据
y = iris.target # 标签数据# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)# 数据标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)# 创建KNN分类器
k = 3 # 选择K值
knn = KNeighborsClassifier(n_neighbors=k)# 训练模型
knn.fit(X_train, y_train)# 进行预测
y_pred = knn.predict(X_test)# 评估模型
print("混淆矩阵:")
print(confusion_matrix(y_test, y_pred))
print("\n分类报告:")
print(classification_report(y_test, y_pred))
print("\n准确率:")
print(accuracy_score(y_test, y_pred))# 输出测试集的真实标签和预测标签
print("\n测试集的真实标签:", y_test)
print("测试集的预测标签:", y_pred)
代码说明
1. 加载数据集
• 使用`load_iris()`函数加载鸢尾花数据集。
• 数据集包含150个样本,每个样本有4个特征,分为3个类别(0、1、2)。
2. 划分训练集和测试集
• 使用`train_test_split()`函数将数据集划分为训练集和测试集,其中测试集占30%。
• 设置`random_state`参数以确保结果的可重复性。
3. 数据标准化
• 使用`StandardScaler`对特征数据进行标准化处理,使每个特征的均值为0,标准差为1。这有助于提高KNN算法的性能。
4. 创建KNN分类器
• 使用`KNeighborsClassifier`创建KNN分类器,设置`n_neighbors=k`,其中`k`是最近邻的数量。
5. 训练模型
• 使用`fit()`方法训练模型。
6. 进行预测
• 使用`predict()`方法对测试集进行预测。
7. 评估模型
• 使用`confusion_matrix`、`classification_report`和`accuracy_score`评估模型的性能。
• 输出混淆矩阵、分类报告和准确率。

注意事项
1. K值的选择
• K值的选择对KNN算法的性能有很大影响。可以通过交叉验证等方法来选择最优的K值。
2. 数据标准化
• 对于KNN算法,数据标准化是非常重要的,因为KNN依赖于距离计算,而不同特征的量纲可能不同。
3. 数据集划分
• 数据集的划分方式可能会影响模型的性能,可以通过多次划分或使用交叉验证来评估模型的稳定性。
相关文章:
k近邻算法K-Nearest Neighbors(KNN)
算法核心 KNN算法的核心思想是“近朱者赤,近墨者黑”。对于一个待分类或预测的样本点,它会查找训练集中与其距离最近的K个样本点(即“最近邻”)。然后根据这K个最近邻的标签信息来对当前样本进行分类或回归。 在分类任务中&#…...
Dubbo(21)如何配置Dubbo的注册中心?
在分布式系统中,注册中心是一个关键组件,用于服务的注册和发现。Dubbo 支持多种注册中心,包括 ZooKeeper、Nacos、Consul、Etcd 等。下面详细介绍如何配置 Dubbo 的注册中心,以 ZooKeeper 为例。 配置步骤 引入依赖:…...
【Android15 ShellTransitions】(九)结束动画+Android原生ANR问题分析
finishTransition这部分的内容不多,并且我个人的实际工作中很少接触这块,因此我之前都觉得没有必要专门开一篇去分析最后留下的这一丁点儿的动画流程。但是最近碰到了一个google原生ANR问题,正好是和这块相关的,也让我意识到了fin…...
如何让DeepSeek-R1在内网稳定运行并实现随时随地远程在线调用
前言:最近,国产AI圈里的新星——Deepseek,简直是火到不行。但是,你是不是已经对那些千篇一律的手机APP和网页版体验感到腻味了?别急,今天就带你解锁一个超炫的操作:在你的Windows电脑上本地部署…...
STM32通用定时器结构框图
STM32单片机快速入门 通用定时器框图 TIM9和TIM12 通用定时器框图 TIM9和TIM12 (二) 通用定时器框图...
How to install vmware workstation pro on Linux mint 22
概述 VMware 是一家专注于虚拟化技术和云计算解决方案的全球领先软件公司,成立于1998年,总部位于美国加州。它的核心技术是通过“虚拟化”将一台物理计算机的硬件资源(如CPU、内存、存储等)分割成多个独立的虚拟环境(…...
深度学习 Deep Learning 第11章 实用方法论
深度学习 Deep Learning 第11章 实用方法论 章节概述 本章深入探讨了机器学习在实际应用中的方法论,强调了从确定目标到逐步优化的系统性过程。在机器学习项目中,明确的目标和性能指标是指导整个开发过程的关键。通过建立初始的端到端系统,…...
【常用的中间件】
中间件(Middleware)是位于客户端和服务器之间的软件层,用于处理客户端请求和服务器响应之间的各种任务。中间件可以提供多种功能,如负载均衡、消息队列、缓存、身份验证等。以下是常用的中间件及其作用: 1. 消息队列中…...
如何排查C++程序的CPU占用过高的问题
文章目录 可能的原因程序设计的BUG系统资源问题恶意软件硬件问题 通常步骤一个简单的问题代码在windows平台上如何排查Windows Process ExplorerWinDBG 在Linux平台如何排查使用TOP GDBPerf 可能的原因 程序设计的BUG 有死循环低效算法与数据结构滥用自旋锁频繁的系统调用&a…...
个人学习编程(3-29) leetcode刷题
最后一个单词的长度: 思路:跳过末尾的空格,可以从后向前遍历 然后再利用 while(i>0 && s[i] ! ) 可以得到字符串的长度, int lengthOfLastWord(char* s) {int length 0;int i strlen(s) - 1; //从字符串末尾开始//…...
Linux云计算SRE-第二十一周
构建单节点prometheus,部署node exporter和mongo exporter。构建kibana大盘。包含主机PU使用率,主机MEM使用率,主机网络包速度。mongo db大盘,包含节点在线状态,读操作延迟等 一、实验环境准备 - 节点信息࿱…...
无人机,云台参数设置,PWM输出控制云台俯仰
目录 1、云台与飞控的连接 2、PX4飞控控制云台,QGC地面站的设置 3、遥控器映射通道设置 4、其他设置 4.1、COM_PREARM_MODE,预解锁模式 4.2、RC9_DZ ,遥控器通道死区设置 1、云台与飞控的连接 首先确定一下,设置飞控第几路…...
EtherCAT转ProfiNet协议转换网关构建西门子PLC与海克斯康机器人的冗余通信链路
一、案例背景 某电子制造企业的5G通信模块组装线,采用西门子S7-1200PLC(ProfiNet主站)进行产线调度,而精密组装工序由3台海克斯康工业机器人(EtherCAT从站)完成。由于协议差异,机器人动作与PLC…...
Android R adb remount 调用流程
目的:调查adb remount 与adb shell进去后执行remount的差异 调试方法:添加log编译adbd,替换system\apex\com.android.adbd\bin\adbd 一、调查adb remount实现 关键代码:system\core\adb\daemon\services.cpp unique_fd daemon_service_to…...
网络中常用协议
一, TCP协议 TCP(Transmission Control Protocol,传输控制协议)是互联网核心协议之一,位于传输层,为应用层提供可靠的、面向连接的数据传输服务。 1. TCP的核心特点 特性说明面向连接通信前需通过三次握手建立连接&a…...
自动驾驶04:点云预处理03
点云组帧 感知算法人员在完成点云的运动畸变补偿后,会发现一个问题:激光雷达发送的点云数据包中的点云数量其实非常少,完全无法用来进行后续感知和定位层面的处理工作。 此时,感知算法人员就需要对这些数据包进行点云组帧的处理…...
Linux内核软中断分析
一、软中断类型 在Linux内核中,中断处理分为上半部(硬中断)和下半部。上半部负责快速响应硬件事件,而下半部用于处理耗时任务,避免阻塞系统。下半部有三种机制:软中断(Softirq)、小任…...
Linux修改默认shell为zsh
一、修改模型shell为zsh 1、检查当前使用的shell echo $SHELL 2、检查当前系统支持的shell cat /etc/shells# 输出结果显示如下: """ /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash /bin/csh /bin/tcsh /usr/bin/csh /usr/bin/tcsh /usr/bin/zsh…...
k8s scheduler几种扩展方式的关系及区别
网上关于scheduler扩展介绍的文章很多,但都是东说一句西说一嘴,完全没有逻辑性,对于逻辑建构者看着很痛苦,这篇文章不会深入教你怎么扩展,而是教你几种扩展方式的关系和逻辑结构: 目前Kubernetes支持五种方…...
react 封装无缝滚动组件
记录,以防忘记 SeamlessScroll.tsx import React, { useEffect, useRef, useState } from react;interface SeamlessScrollProps {children: React.ReactNode;speed?: number; // 滚动速度,单位:像素/秒minItems?: number; // 最小项目数…...
[ComfyUI] 如何升级自定义节点(Custom Nodes)
ComfyUI 提供了灵活的 自定义节点(Custom Nodes) 功能,允许用户扩展其能力。随着插件的更新,保持 Custom Nodes 处于最新状态是确保兼容性和功能完整性的关键。 1. 手动升级(Git Pull 方式) 如果你的 自定义节点 是通过 Git 克隆的,可以使用 Git 命令来升级: 步骤: …...
软件项目管理课程之第4讲:软件需求管理
讲授内容 项目案例 软件需求管理的基本概念 软件需求开发 软件需求管理 项目案例 案例背景:小王作为软件项目负责人,带领团队开展需求调查工作,但在需求分析和后续开发过程中出现了一系列问题。 问题表现: 项目规模庞大&…...
深入理解 dispatchEvent:前端事件触发的艺术
dispatchEvent 是 DOM 元素的一个方法,用于手动触发/派发一个事件。这个方法允许开发者以编程方式触发事件,而不是等待用户交互或浏览器自动触发。 1.基本概念 ★ 基础 作用:dispatchEvent 用于在指定的 DOM 节点上触发一个事件 使用场景&a…...
linux和windows是采用何种机制保存密码的?
传统Linux的不足: 1)存在特权用户root 任何人只要得到root的权限,对于整个系统都可以为所欲为。这一点Windows也一样。 2)对于文件的访问权划分不够细 在linux系统里,对于文件的操作,只有「所有者」…...
matlab打开两个工程
1、问题描述 写代码时,需要实时参考别人的代码,需要同时打开2个模型,当模型在同一个工程内时,这是可以直接打开的,如图所示 2、解决方案 再打开一个MATLAB主窗口 这个时候就可以同时打开多个模型了 3、正确的打开方…...
Unity中的MaterialPropertyBlock的作用和 Material 的区别
MaterialPropertyBlock 是 Unity 提供的一个用于动态修改材质属性的轻量级工具,核心作用是避免材质实例化(Material Instantiation),从而优化性能。以下是它的关键特性和使用方法: 1. 核心作用 避免材质实例化 直接修改…...
Python与文件——保存文件
1.以下关于Python二维数据的描述中,错误的是()。 A、CSV文件的每一行是一维数据,可以用列表、元组表示。 B、从CSV文件获得数据内容后,可以用replace()来去掉每行最后的换行符。 C、若一个列表变量里的元素都是字符串类型,则可以用join()合成字符串。 D、列表中保存的二维数据,…...
HarmonyOS主题管理工具封装:动态切换、持久化存储与常见问题解析
注:适用版本(Harmony OS NEXT / 5.0 / API 12 ) 一、效果展示 二、技术栈 HarmonyOS ArkUI框架 使用AppStorage实现跨组件状态管理,PersistentStorage持久化存储用户偏好。 系统配置常量 ConfigurationConstant.Color…...
60V单通道高精度线性恒流LED驱动器防60V反接SOD123封装
产品描述: PC561A 系列产品是用于产生单通道、高精度恒流源( Constant Current Regulator, CCR) 的LED 驱动芯片,为各类 LED 照明应用提供高性价比恒流方案。PC561A 采用晶体管自偏置技术,可在超宽工作电压范围内维持…...
学习threejs,使用Sprite精灵、SpriteMaterial精灵材质
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.Sprite1.1.1 ☘️代码…...
