草庐IT

基于Matlab的K-近邻算法(KNN)详解(附算法介绍及代码详解)

数字地学新视界 2024-07-28 原文

一、内容提要

今天笔者同样以测井岩性分类为实例,为大家分享一种被称为“最简单的机器学习算法之一”的K-近邻算法(K-Nearest Neighbor, KNN)。

K-近邻算法(KNN,K-Nearest Neighbor)可以用于分类和回归[1]。K-近邻算法,意思是每一个样本都可以用它最接近的K个邻居来代表,以大多数邻居的特征代表该样本的特征,据此分类[2]。它的优势非常突出:思路简单、易于理解、易于实现,无需参数估计[3]。

本期笔者将KNN算法应用在基于测井数据的岩性分类上。

下面分为算法简介、实例计算与代码解读三个部分进行讲解。(代码获取方式详见文末)

二、算法简介

K-近邻算法

K-近邻算法的计算过程是:一个未知分类的样本进入数据集、那么与它最相似(特征空间中最邻近)的K个样本的类别大多数是哪一类,那么它就是哪一类。K-近邻算法的主要流程如下:

1)存在一个训练样本集,训练集中每个样本都已知所属的分类,指定最近邻居数K。
2)输入没有分类的新样本后,将新样本的每个属性与训练集中的样本对应的属性进行比较,然后提取最相近的K个样本的分类;
3)这K个样本出现最多的分类就是新数据的分类。

下面我们举一个对《未知》小说进行分类的例子,来解释K-临近算法的主要流程(见下表)。

 有六篇中篇小说,根据小说中枪战次数和接吻次数(特征)(虚构数据)归类为言情小说或黑帮小说。由于《未知》的接吻片段次数多、枪战片段次数少,于是将《未知》与言情小说归为一类。通过这个例子我们可以发现,K-近邻算法是不需要训练过程的,而且是没有参数估计的。

在算法的实现中,我们使用matlab自带的“鸢尾花的分类”例子,来展示KNN算法是如何被实现的。如图所示,鸢尾花数据集每个样本有两个特征,可用散点的形式绘制在二维平面上;对应三种分类(setosa,versicolor和virginica)。现在插入三个新样本(使用▽标识),并根据KNN的方法对其进行分类。

图1:鸢尾花数据集分类(matlab)

如算法简介中介绍,只需要计算3个新样本与全部训练集数据的距离,再进行类别统计即可,这样的做法在数据量极大的时候效率很低。这时,如果将所有数据点之间的位置关系建立联系——KD树(K-Dimensional Tree,KDTree),在搜索新样本的最邻近点时从树的根节点一步一步向叶节点搜索,就能以更高的效率搜索到最临近点。

对KDTree生成和查询的详细步骤不多做赘述,这里我们使用github上的matlab kdtree可视化库对KDTree进行可视化,给大家提供直观的认识,不做重点介绍。生成kdtree并可视化的代码如下:

function tree_output = kd_buildtree(X,plot_stuff,parent_number,split_dimension)

在二维空间中,KDTree表示为如图2所示的,不断分割二维平面的模式。当有新样本加入集合中,就放入二维平面(多维数据为超平面)的对应区域中,通过搜索能很快搜索到K个近邻点。

图2:KDTree

三、实例计算

实例:基于六条测井曲线,对岩性进行划分。训练集如图3所示。

数据:训练集由3300个深度的测井曲线以及对应的岩性分类组成。则每一个深度看作一个样本,测井曲线的数值作为属性、岩性作为分类结果。367个深度的测井曲线以及对应的岩性分类作为测试集,测试建立的模型性能。

目的:基于六条测井曲线数据构建一个KNN模型,用于岩性类型划分。

图3:基于测井数据的岩性识别结果示意图

四、代码解读

第一步 数据导入

%% 数据导入
load traindata.mat
load testdata.mat

第二步 建立
使用训练数据集构造KDTree

x = traindata(:,1:6);
Mdl = KDTreeSearcher(x);

第三步 寻找测试集K个邻居
使用KDTree 结构体MDI,得到n,n为样本数x邻居数的矩阵,每一行对应一个测试样本,这一行的所有元素代表最邻近的训练集样本点的索引

[n,~] = knnsearch(Mdl,testdata(:,1:6),'k',k);

第四步 循环提取测试集样本对应邻居
循环提取测试样本的邻居,并统计众数进行投票,得到最终分类结果。使用validate计算最终的准确率分类。其中mode用于计算最近邻点分类向量tempClass中的众数。

for i = 1:size(n,1)

    tempClass = traindata(n(i,:),7);
    result = mode(tempClass);
    resultClass(i,1) = result;

end

validate = sum( testdata(:,7) == resultClass )./ size(testdata,1) * 100;

第五步 对K进行优化调参

将以上过程封装为函数myKNNCLass,将k作为参数进行调参,由于需要使用众数作为结果,因此邻居数应该选择为奇数。

for kValue = 1:2:15
    validate = myKNNCLass(traindata,testdata,kValue);
    disp(['取近邻数K = ' num2str(kValue),'; 此时的准确率为 ' num2str(validate) '%'])
end

得到结果 >>

取近邻数K = 1; 此时的准确率为 90.9836%

取近邻数K = 3; 此时的准确率为 87.9781%

取近邻数K = 5; 此时的准确率为 84.153%

取近邻数K = 7; 此时的准确率为 84.9727%

取近邻数K = 9; 此时的准确率为 82.2404%

取近邻数K = 11; 此时的准确率为 80.0546%

取近邻数K = 13; 此时的准确率为 79.235%

取近邻数K = 15; 此时的准确率为 77.8689%

则最后使用取近邻数1为最好。

参考文献

[1]  Altman, N. S. An introduction to kernel and nearest-neighbor nonparametric regression. The American Statistician. 1992, 46 (3): 175–185. doi:10.1080/00031305.1992.10475879.

[2]  田翠华著,基于GT4的物联网交通信息服务仿真研究,厦门大学出版社,2017.01,第225页

[3]  宋园,陈永平. 聚类分析中K-邻近算法的研究. 《 CNKI;WanFang 》 , 2013

【注】此文章版权归数字地学新视界账号所有,如需转载务必联系后台管理员。否则将维权到底。

代码获取方式 :

关注公众号并联系数字地学新视界微信后台管理员,可领取完整版带有详尽注释的示例代码!

[如何获取管理员联系方式]:菜单栏中的联系我们——>转载须知,扫码添加即可。

知识创作分享不易,希望与大家共同成长进步~​​​​​​​ 【多见多闻】| 基于K-近邻算法(KNN)的岩性分类实战详解K-近邻算法;KDTree;测井数据;岩性识别https://mp.weixin.qq.com/s/4R9mlSvnarw8kQa21NNhMQ

有关基于Matlab的K-近邻算法(KNN)详解(附算法介绍及代码详解)的更多相关文章

  1. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  2. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  3. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

  4. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  5. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  6. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  7. 程序员如何提高代码能力? - 2

    前言作为一名程序员,自己的本质工作就是做程序开发,那么程序开发的时候最直接的体现就是代码,检验一个程序员技术水平的一个核心环节就是开发时候的代码能力。众所周知,程序开发的水平提升是一个循序渐进的过程,每一位程序员都是从“菜鸟”变成“大神”的,所以程序员在程序开发过程中的代码能力也是根据平时开发中的业务实践来积累和提升的。提高代码能力核心要素程序员要想提高自身代码能力,尤其是新晋程序员的代码能力有很大的提升空间的时候,需要针对性的去提高自己的代码能力。提高代码能力其实有几个比较关键的点,只要把握住这些方面,就能很好的、快速的提高自己的一部分代码能力。1、多去阅读开源项目,如有机会可以亲自参与开源

  8. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  9. Matlab imread()读到了什么 (浅显 当复习文档了) - 2

    matlab打开matlab,用最简单的imread方法读取一个图像clcclearimg_h=imread('hua.jpg');返回一个数组(矩阵),往往是a*b*cunit8类型解释一下这个三维数组的意思,行数、数和层数,unit8:指数据类型,无符号八位整形,可理解为0~2^8的数三个层数分别代表RGB三个通道图像rgb最常用的是24-位实现方法,即RGB每个通道有256色阶(2^8)。基于这样的24-位RGB模型的色彩空间可以表现256×256×256≈1670万色当imshow传入了一个二维数组,它将以灰度方式绘制;可以把图像拆分为rgb三层,可以以灰度的方式观察它figure(1

  10. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

随机推荐