当前位置: 首页 > news >正文

<K-近邻算法(KNN)>——《机器学习算法初识》

目录

一、 K-近邻算法简介

1 什么是K-近邻算法

1.1 K-近邻算法(KNN)概念

1.2 KNN算法流程总结

二、 k近邻算法api初步使用

 1 Scikit-learn工具介绍

1.1 Scikit-learn包含的内容

2 K-近邻算法API

3 小结

三、 k值的选择

1 K值选择说明

2 小结

四、 kd树

1 kd树简介

1.1 什么是kd树

1.2 原理

2 构造方法

3 总结

五、 特征工程-特征预处理

1 什么是特征预处理

1.1 特征预处理定义

为什么我们要进行归一化/标准化?

1.2 包含内容(数值型数据的无量纲化)

1.3 特征预处理API

2 归一化

2.1 定义

2.2 公式

2.3 归一化总结

3 标准化

3.1 定义

3.2 公式

3.3 标准化总结

4 总结

六、 交叉验证,网格搜索

1 什么是交叉验证(cross validation)

1.1 分析

1.2 为什么需要交叉验证

问题:这个只是让被评估的模型更加准确可信,那么怎么选择或者调优参数呢?

2 什么是网格搜索(Grid Search)

3 交叉验证,网格搜索(模型选择与调优)API:

4 总结

七、k近邻算法总结

优点:

缺点:

方法思想:


一、 K-近邻算法简介

1 什么是K-近邻算法

1.1 K-近邻算法(KNN)概念

K Nearest Neighbor算法又叫KNN算法,这个算法是机器学习里面一个比较经典的算法, 总体来说KNN算法是相对比较容易理解的算法。

  • 定义

如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。

来源:KNN算法最早是由Cover和Hart提出的一种分类算法

  • 距离公式

两个样本的距离可以通过如下公式计算,又叫欧式距离 。  

1.2 KNN算法流程总结

1)计算已知类别数据集中的点与当前点之间的距离

2)按距离递增次序排序

3)选取与当前点距离最小的k个点

4)统计前k个点所在的类别出现的频率

5)返回前k个点出现频率最高的类别作为当前点的预测分类

二、 k近邻算法api初步使用

 1 Scikit-learn工具介绍

  • Python语言的机器学习工具
  • Scikit-learn包括许多知名的机器学习算法的实现
  • Scikit-learn文档完善,容易上手,丰富的API

1.1 Scikit-learn包含的内容

  • 分类、聚类、回归
  • 特征工程
  • 模型选择、调优

2 K-近邻算法API

  • sklearn.neighbors.KNeighborsClassifier(n_neighbors=5)
    • n_neighbors:int,可选(默认= 5),k_neighbors查询默认使用的邻居数

3 小结

  • sklearn的优势:
    • 文档多,且规范
    • 包含的算法多
    • 实现起来容易
  • knn中的api
    • sklearn.neighbors.KNeighborsClassifier(n_neighbors=5)

三、 k值的选择

1 K值选择说明

  • K值过小
    • 容易受到异常点的影响
  • k值过大:
    • 受到样本均衡的问题

K值选择问题,李航博士的一书「统计学习方法」上所说:

1) 选择较小的K值,就相当于用较小的领域中的训练实例进行预测,“学习”近似误差会减小,只有与输入实例较近或相似的训练实例才会对预测结果起作用,与此同时带来的问题是“学习”的估计误差会增大,换句话说,K值的减小就意味着整体模型变得复杂,容易发生过拟合;

2) 选择较大的K值,就相当于用较大领域中的训练实例进行预测,其优点是可以减少学习的估计误差,但缺点是学习的近似误差会增大。这时候,与输入实例较远(不相似的)训练实例也会对预测器作用,使预测发生错误,且K值的增大就意味着整体的模型变得简单。

3) K=N(N为训练样本个数),则完全不足取,因为此时无论输入实例是什么,都只是简单的预测它属于在训练实例中最多的类,模型过于简单,忽略了训练实例中大量有用信息。

实际应用中,K值一般取一个比较小的数值,例如采用交叉验证法(简单来说,就是把训练数据在分成两组:训练集和验证集)来选择最优的K值。

  • 近似误差
    • 对现有训练集的训练误差,关注训练集
    • 如果近似误差过小可能会出现过拟合的现象,对现有的训练集能有很好的预测,但是对未知的测试样本将会出现较大偏差的预测。
    • 模型本身不是最接近最佳模型。
  • 估计误差
    • 可以理解为对测试集的测试误差,关注测试集,
    • 估计误差小说明对未知数据的预测能力好,
    • 模型本身最接近最佳模型。

2 小结

  • KNN中K值大小选择对模型的影响
    • K值过小
      • 容易受到异常点的影响
      • 容易过拟合
    • k值过大:
      • 受到样本均衡的问题
      • 容易欠拟合

四、 kd树

问题导入:

实现k近邻算法时,主要考虑的问题是如何对训练数据进行快速k近邻搜索。

这在特征空间的维数大及训练数据容量大时尤其必要。

k近邻法最简单的实现是线性扫描(穷举搜索),即要计算输入实例与每一个训练实例的距离。计算并存储好以后,再查找K近邻。当训练集很大时,计算非常耗时。

为了提高kNN搜索的效率,可以考虑使用特殊的结构存储训练数据,以减小计算距离的次数。

1 kd树简介

1.1 什么是kd树

根据KNN每次需要预测一个点时,我们都需要计算训练数据集里每个点到这个点的距离,然后选出距离最近的k个点进行投票。当数据集很大时,这个计算成本非常高

kd树:为了避免每次都重新计算一遍距离,算法会把距离信息保存在一棵树里,这样在计算之前从树里查询距离信息,尽量避免重新计算。其基本原理是,如果A和B距离很远,B和C距离很近,那么A和C的距离也很远。有了这个信息,就可以在合适的时候跳过距离远的点。

这样优化后的算法复杂度可降低到O(DNlog(N))。可参阅论文:Bentley,J.L.,Communications of the ACM(1975)。

1989年,另外一种称为Ball Tree的算法,在kd Tree的基础上对性能进一步进行了优化。可以搜索Five balltree construction algorithms来了解详细的算法信息。

1.2 原理

黄色的点作为根节点,上面的点归左子树,下面的点归右子树,接下来再不断地划分,分割的那条线叫做分割超平面(splitting hyperplane),在一维中是一个点,二维中是线,三维的是面。

黄色节点就是Root节点,下一层是红色,再下一层是绿色,再下一层是蓝色。

1.树的建立;

2.最近邻域搜索(Nearest-Neighbor Lookup)

kd树(K-dimension tree)是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是一种二叉树,表示对k维空间的一个划分,构造kd树相当于不断地用垂直于坐标轴的超平面将K维空间切分,构成一系列的K维超矩形区域。kd树的每个结点对应于一个k维超矩形区域。利用kd树可以省去对大部分数据点的搜索,从而减少搜索的计算量。

类比“二分查找”:给出一组数据:[9 1 4 7 2 5 0 3 8],要查找8。如果挨个查找(线性扫描),那么将会把数据集都遍历一遍。而如果排一下序那数据集就变成了:[0 1 2 3 4 5 6 7 8 9],按前一种方式我们进行了很多没有必要的查找,现在如果我们以5为分界点,那么数据集就被划分为了左右两个“簇” [0 1 2 3 4]和[6 7 8 9]。

因此,根本就没有必要进入第一个簇,可以直接进入第二个簇进行查找。把二分查找中的数据点换成k维数据点,这样的划分就变成了用超平面对k维空间的划分。空间划分就是对数据点进行分类,“挨得近”的数据点就在一个空间里面。

2 构造方法

(1)构造根结点,使根结点对应于K维空间中包含所有实例点的超矩形区域;

(2)通过递归的方法,不断地对k维空间进行切分,生成子结点。在超矩形区域上选择一个坐标轴和在此坐标轴上的一个切分点,确定一个超平面,这个超平面通过选定的切分点并垂直于选定的坐标轴,将当前超矩形区域切分为左右两个子区域(子结点);这时,实例被分到两个子区域。

(3)上述过程直到子区域内没有实例时终止(终止时的结点为叶结点)。在此过程中,将实例保存在相应的结点上。

(4)通常,循环的选择坐标轴对空间切分,选择训练实例点在坐标轴上的中位数为切分点,这样得到的kd树是平衡的(平衡二叉树:它是一棵空树,或其左子树和右子树的深度之差的绝对值不超过1,且它的左子树和右子树都是平衡二叉树)。

KD树中每个节点是一个向量,和二叉树按照数的大小划分不同的是,KD树每层需要选定向量中的某一维,然后根据这一维按左小右大的方式划分数据。在构建KD树时,关键需要解决2个问题:

(1)选择向量的哪一维进行划分;

(2)如何划分数据;

第一个问题简单的解决方法可以是随机选择某一维或按顺序选择,但是更好的方法应该是在数据比较分散的那一维进行划分(分散的程度可以根据方差来衡量)

第二个问题中,好的划分方法可以使构建的树比较平衡,可以每次选择中位数来进行划分。

3 总结

  • kd树的构建过程
    • 1.构造根节点
    • 2.通过递归的方法,不断地对k维空间进行切分,生成子节点
    • 3.重复第二步骤,直到子区域中没有示例时终止
    • 需要关注细节:a.选择向量的哪一维进行划分;b.如何划分数据
  • kd树的搜索过程
    • 1.二叉树搜索比较待查询节点和分裂节点的分裂维的值,(小于等于就进入左子树分支,大于就进入右子树分支直到叶子结点)
    • 2.顺着“搜索路径”找到最近邻的近似点
    • 3.回溯搜索路径,并判断搜索路径上的结点的其他子结点空间中是否可能有距离查询点更近的数据点,如果有可能,则需要跳到其他子结点空间中去搜索
    • 4.重复这个过程直到搜索路径为空

五、 特征工程-特征预处理

1 什么是特征预处理

1.1 特征预处理定义

通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程。

  • 为什么我们要进行归一化/标准化?
    • 特征的单位或者大小相差较大,或者某特征的方差相比其他的特征要大出几个数量级容易影响(支配)目标结果,使得一些算法无法学习到其它的特征

1.2 包含内容(数值型数据的无量纲化)

  • 归一化
  • 标准化

1.3 特征预处理API

 sklearn.preprocessing

2 归一化

2.1 定义

通过对原始数据进行变换把数据映射到(默认为[0,1])之间

2.2 公式

作用于每一列,max为一列的最大值,min为一列的最小值,那么X’’为最终结果,mx,mi分别为指定区间值默认mx为1,mi为0 

那么怎么理解这个过程呢?我们通过一个例子 :

2.3 归一化总结

注意最大值最小值是变化的,另外,最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性较差,只适合传统精确小数据场景。

怎么办?

3 标准化

3.1 定义

通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内

3.2 公式

作用于每一列,mean为平均值,σ为标准差

所以回到刚才异常点的地方,我们再来看看标准化

  • 对于归一化来说:如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变
  • 对于标准化来说:如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改变较小。

3.3 标准化总结

在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景。

4 总结

  • 什么是特征工程
    • 定义
      • 通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程
    • 包含内容:
      • 归一化
      • 标准化
  • 归一化
    • 定义:
      • 对原始数据进行变换把数据映射到(默认为[0,1])之间
    • api:
      • sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )
      • 参数:feature_range -- 自己指定范围,默认0-1
    • 总结:
      • 鲁棒性比较差(容易受到异常点的影响)
      • 只适合传统精确小数据场景(实际开发中较少使用)
  • 标准化
    • 定义:
      • 对原始数据进行变换把数据变换到均值为0,标准差为1范围内
    • api:
      • sklearn.preprocessing.StandardScaler( )
    • 总结:
      • 异常值对我影响小
      • 适合现代嘈杂大数据场景(实际开发中较多使用)

六、 交叉验证,网格搜索

1 什么是交叉验证(cross validation)

交叉验证:将拿到的训练数据,分为训练和验证集。以下图为例:将数据分成4份,其中一份作为验证集。然后经过4次(组)的测试,每次都更换不同的验证集。即得到4组模型的结果,取平均值作为最终结果。又称4折交叉验证。

1.1 分析

我们之前知道数据分为训练集和测试集,但是为了让从训练得到模型结果更加准确。做以下处理

  • 训练集:训练集+验证集
  • 测试集:测试集

1.2 为什么需要交叉验证

交叉验证目的:为了让被评估的模型更加准确可信

问题:这个只是让被评估的模型更加准确可信,那么怎么选择或者调优参数呢?

通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。

 

3 交叉验证,网格搜索(模型选择与调优)API:

  • sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)
    • 对估计器的指定参数值进行详尽搜索
    • estimator:估计器对象
    • param_grid:估计器参数(dict){“n_neighbors”:[1,3,5]}
    • cv:指定几折交叉验证
    • fit:输入训练数据
    • score:准确率
    • 结果分析:
      • bestscore__:在交叉验证中验证的最好结果
      • bestestimator:最好的参数模型
      • cvresults:每次交叉验证后的验证集准确率结果和训练集准确率结果

4 总结

  • 交叉验证
    • 定义:
      • 将拿到的训练数据,分为训练和验证集
      • *折交叉验证
    • 分割方式:
      • 训练集:训练集+验证集
      • 测试集:测试集
    • 为什么需要交叉验证
      • 为了让被评估的模型更加准确可信
      • 注意:交叉验证不能提高模型的准确率
  • 网格搜索
    • 超参数:
      • sklearn中,需要手动指定的参数,叫做超参数
    • 网格搜索就是把这些超参数的值,通过字典的形式传递进去,然后进行选择最优值
  • api
    • sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)
      • estimator -- 选择了哪个训练模型
      • param_grid -- 需要传递的超参数
      • cv -- 几折交叉验证

七、k近邻算法总结

  • 优点:
    • 简单有效
    • 重新训练的代价低
    • 适合类域交叉样本
      • KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
    • 适合大样本自动分类
      • 该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分。
  • 缺点:
    • 惰性学习
      • KNN算法是懒散学习方法(lazy learning,基本上不学习),一些积极学习的算法要快很多
    • 类别评分不是规格化
      • 不像一些通过概率评分的分类
    • 输出可解释性不强
      • 例如决策树的输出可解释性就较强
    • 对不均衡的样本不擅长
      • 当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。
    • 计算量较大
      • 目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。
方法思想
  • 使用可视化加载和探索数据,以确定特征是否能将不同类别分开。
  • 通过标准化数字特征并随机抽样到训练集和测试集来准备数据。
  • 通过统计学,精确度度量进行构建和评估机器学习模型。

 后记:
●本博客基于B站开源学习资源,是作者学习的笔记记录,仅用于学习交流,不做任何商业用途! 

相关文章:

  • 【dart】常用数据类型
  • 探索HDFS读写流程、节点机制和数据完整性
  • 基于EasyCVR视频技术的流媒体视频融合与汇聚管理系统建设方案
  • 【ARM linux mqtt协议连接服务器】
  • 16 OpenCV Laplance算子
  • 初识Spring MVC
  • 【数据挖掘】练习1:R入门
  • 自然语言处理(NLP)—— 语义关系提取
  • HTML 学习笔记(九)颜色值和长度单位
  • ThingsBoard开源物联网平台介绍
  • python3:No module named ‘pandas‘
  • LeetCode454 四数相加
  • 用Docker Compose实现负载均衡【入门篇】
  • 数据库管理-第160期 Oracle Vector DB AI-11(20240312)
  • STM32外设分类--学习笔记
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • Android 架构优化~MVP 架构改造
  • CSS实用技巧
  • docker容器内的网络抓包
  • happypack两次报错的问题
  • JDK 6和JDK 7中的substring()方法
  • Python 反序列化安全问题(二)
  • SQL 难点解决:记录的引用
  • vue数据传递--我有特殊的实现技巧
  • 服务器从安装到部署全过程(二)
  • 浮动相关
  • 给第三方使用接口的 URL 签名实现
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 驱动程序原理
  • 如何邀请好友注册您的网站(模拟百度网盘)
  • 使用 Docker 部署 Spring Boot项目
  • 微信小程序填坑清单
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 物联网链路协议
  • 小程序开发之路(一)
  • 一道闭包题引发的思考
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • #stm32整理(一)flash读写
  • ()、[]、{}、(())、[[]]命令替换
  • (11)MATLAB PCA+SVM 人脸识别
  • (C++20) consteval立即函数
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (Java实习生)每日10道面试题打卡——JavaWeb篇
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (独孤九剑)--文件系统
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (七)Knockout 创建自定义绑定
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (一) springboot详细介绍
  • (一)WLAN定义和基本架构转
  • .NET CLR Hosting 简介
  • .NET Framework 4.6.2改进了WPF和安全性