机器学习作业二之KNN算法

KNN(K- Nearest Neighbor)法即K最邻近法,最初由 Cover和Hart于1968年提出,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路非常简单直观:如果一个样本在特征空间中的K个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别 。

该方法的不足之处是计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最邻近点。目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。另外还有一种 Reverse KNN法,它能降低KNN算法的计算复杂度,提高分类的效率 。

KNN算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分 。

——百度百科

一、算法思想:

(算法名字中含有Nearest Neighbor,最近的邻居,可以想想一下一个人刚到一片陌生的地方,想要熟悉这个地方的一种方法就是找几个最近的邻居来了解这块地方。)

个人概括的正式一点的解释:

已经有的样本,均有n个特征值,可以用n个坐标轴表示出这个样本点的位置。

而测试集中的元素,也均有n个特征值,也可以用n个坐标轴表示出这个样本点的位置。

对于每个测试集中的元素,找到距离其最近的k个点(距离可使用欧氏距离d(x, y) = \sqrt{\sum_{i=1}^{n} (x_i - y_i)^2}),在这k个点中选出数量最多的一个种类,将这个种类作为其结果。

需要注意的是,由于每个坐标的相对大小不同, 需要将数值做归一化处理。


二、代码

思想不难,代码:

(代码下方有各个函数的解释)

import csv
import math
import operator

from matplotlib import pyplot as plt

def guiyihua(train, input):
    maxval1 = 0
    minval1 = 101
    maxval2 = 0
    minval2 = 101
    for i in range( len(train) ):
        train[i][0] = float(train[i][0])
        train[i][1] = float(train[i][1])
        maxval1 = max(maxval1, train[i][0])
        minval1 = min(minval1, train[i][0])
        maxval2 = max(maxval2, train[i][1])
        minval2 = min(minval2, train[i][1])
    for i in range( len(input) ):
        input[i][0] = float(input[i][0])
        input[i][1] = float(input[i][1])
        maxval1 = max(maxval1, input[i][0])
        minval1 = min(minval1, input[i][0])
        maxval2 = max(maxval2, input[i][1])
        minval2 = min(minval2, input[i][1])
    for i in range( len(train)):
        train[i][0] = (train[i][0]-minval1)/(maxval1-minval1)
        train[i][1] = (train[i][1]-minval2)/(maxval2-minval2)
    for i in range( len(input) ):
        input[i][0] = (input[i][0]-minval1)/(maxval1-minval1)
        input[i][1] = (input[i][1]-minval2)/(maxval2-minval2)

def load(fname):
    with open(fname, 'rt') as csvfile:
        lists = csv.reader(csvfile)
        data = list(lists)
        return data
    
def euclideanDistance(atrain, ainput, needcal):
    re2 = 0
    for i in range(needcal):
        re2 += (atrain[i] - ainput[i])**2
    return math.sqrt(re2)

def jg(train, ainput, k):
    alldis = []
    needcal = len(ainput)-1 #需要计算的维度
    for i in range(len(train)):
        nowdis = euclideanDistance(train[i], ainput, needcal)
        alldis.append((train[i], nowdis))
    alldis.sort(key=operator.itemgetter(1))
    
    vote = {}
    for i in range(k):
        type = alldis[i][0][-1]
        if type in vote:
            vote[type] += 1
        else:
            vote[type] = 1
        
    sortvote = sorted(vote.items(), key=operator.itemgetter(1), reverse=True)#items()将字典转为列表,这样可以对第二个值进行排序
    return sortvote[0][0]
 
def showright(train, input):
    plt.subplot(2, 5, 1)
    plt.title("right")
    for i in range(len(train)):
        if train[i][-1] == "第一种" :  
            plt.scatter(train[i][0], train[i][1], c = '#0066FF', s = 10, label = "第一种")
        else :
            plt.scatter(train[i][0], train[i][1], c = '#CC0000', s = 10, label = "第二种")
    for i in range(len(input)):
        if input[i][-1] == "第一种" :
            plt.scatter(input[i][0], input[i][1], c = '#0066FF', s = 50, label = "cs第一种")
            #plt.scatter(input[i][0], input[i][1], c = '#FF3333', s = 30, label = "cs第一种")
        else :
            plt.scatter(input[i][0], input[i][1], c = '#CC0000', s = 50, label = "cs第一种")
            #plt.scatter(input[i][0], input[i][1], c = '#FF33FF', s = 30, label = "cs第二种")

def showtest(train, input, re, ki, cnt):
    plt.subplot(2, 5, ki+1)
    plt.title("k = "+ repr(ki)+" acc: "+repr(1.0*cnt/(1.0*len(input))*100 )+ '%')
    for i in range(len(train)):
        if train[i][-1] == "第一种" :
            plt.scatter(train[i][0], train[i][1], c = '#0066FF', s = 10, label = "第一种")
        else :
            plt.scatter(train[i][0], train[i][1], c = '#CC0000', s = 10, label = "第二种")
    for i in range(len(input)):
        if re[i] == "第一种" :
            plt.scatter(input[i][0], input[i][1], c = '#0066FF', s = 50, label = "cs第一种")
            #plt.scatter(input[i][0], input[i][1], c = '#00FF33', s = 30, label = "cs第一种")
        else :
            plt.scatter(input[i][0], input[i][1], c = '#CC0000', s = 50, label = "cs第二种")
            #plt.scatter(input[i][0], input[i][1], c = '#00FFFF', s = 30, label = "cs第二种")
def main():
    train = load("C:\\Users\\T.HLQ12\\Desktop\\wdnmd\\python\\jiqixuexi\\train.csv")
    input = load("C:\\Users\\T.HLQ12\\Desktop\\wdnmd\\python\\jiqixuexi\\test.csv")
    guiyihua(train, input)
    # print(train)
    # print(input)
    showright(train, input)
    for ki in range (1, 10):
        re = []
        k = ki
        cnt = 0
        for i in range(len(input)):
            type = jg(train, input[i], k)
            if(type == input[i][-1]):
                cnt += 1
            re.append(type)
            print("预测:" + type + ",实际上: " + input[i][-1])
        print("准确率: " + repr(1.0*cnt/(1.0*len(input))*100) + '%')
        showtest(train, input, re, ki, cnt)
    plt.show()
main()
    

逐个解释一下:

guiyihua:

不会归一化的英文,就写拼音了,从训练集和测试集中找出一个最大值和最小值。然后把训练集和测试集的数据都减去最小值,再除以最大值减最小值即可。

load:

使用with open可以不用人为关闭文件。其中csv.reader会返回一个迭代器,配合list将data赋值为二维数组。

euclideanDistance:

欧式距离,就是把所有维度平方下相加,然后再返回开根号的值。

jg:

这个是judge的缩写,判断输入的测试集中的一个元素的种类。函数的参数有训练集,一个输入的值和一个k。遍历训练集中的所有元素,算出距离测试点的欧式距离,然后添加到alldis数组里。最后对数组进行排序(参数中意味按照元组中第一个值排序,默认从大到小)。然后创建一个vote字典。这个字点的第一个值是种类,第二个值是种类的个数。循环遍历距离数组,每次碰到一个种类,就把这个种类的数量加一。循环结束后,对这个字典的第二个值进行排序(排序中参数:第一个item:将字典vote转换为一个包含键值对的列表, 第二个:对下标1进行排序,第三个:从大到小排序),选出最大数量的种类作为这个测试元素的结果。

shoright 与showtest:

这两个函数是用于绘制散点图的。Subplot中第一个参数是行数,第二个参数是列数。第三个参数是第几个部分。Title中可以设置这张图的标题。训练集中每个种类的颜色都不一样,点是使用scatter打上去的,其中第一个参数是这个点在第一条坐标轴上对应的值。第二个点是第二个坐标轴上对应的值,c是颜色。S是点的大小。 label是这个点的标签。循环遍历训练集和测试的每个点,就可以绘制出一张散点图。

三、实际问题

一、

如图所示,这个报错是因为vote中不存在vote括号中的值,修改为:

即可。

二、

这个问题不知道发生的原因是什么,查询资料本来以为是scatter可以使用切分,但是实际上没有办法使用,最后就替换成了循环遍历每个点来绘制散点图的方式。

四、实验结论

结果:(第一张图为对的。对于每张图,大的是测试集,小的是训练集,颜色相同的是一个种类)

数据:

从结果分析上来看,K在1~9范围内,不能很好的确定最优值,需要多次取值,反复确认才能锁定k值。

尽管KNN算法有着计算量大,维度灾难等缺点,但是可以不用训练,容易理解,对于新手来说很友好。

(纯手打,求老师轻点批改)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vs2022 关于Python项目无法识别中文的解决方法

这是针对于vs2022安装和使用教程(详细)-CSDN博客 Python项目无法识别中文的解决方法的文章 一、问题 1.输入代码 print("你好Hello world!") 2.启动,发现代码里有中文报错 二、解决方法 1.选择菜单栏里的工具->…

超实用的Maven指南

文章目录 实战记录📝Maven 指令大全 🌟找到没有被使用的jar(analyze)分析jar是被哪个maven引入(tree)🌟 dependencies(Maven依赖)build-resources(资源导入&a…

如何提高知识库系统管理水平?

我们都有过这样的经历--遇到问题或紧急请求时,第一时间就是向知识库系统寻求帮助。很多时候,当你翻遍了无穷无尽的文档,却发现没有任何东西能够摆脱此时的困境,这时,向服务台提交工单成了不可避免的解决方式&#xff0…

基于Java的新生入学报到管理系统的设计与实现(论文+源码+PPT)_kaic

摘 要 21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识,科学化的管理,使信息…

2024年2月游戏手柄线上电商(京东天猫淘宝)综合热销排行榜

鲸参谋监测的线上电商(京东天猫淘宝)游戏手柄品牌销售数据已出炉!2月游戏手柄销售数据呈现出强劲的增长势头。 根据鲸参谋数据显示,今年2月游戏手柄月销售量累计约43万件,同比去年上涨了78%;销售额累计达1…

Stable Diffusion 模型分享:SDXL Unstable Diffusers ☛ YamerMIX(混合风格)

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里,订阅后可阅读专栏内所有文章。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八下载地址模型介绍

每日一题 --- 快乐数[力扣][Go]

快乐数 题目:202. 快乐数 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到…

Spring用到了哪些设计模式?

目录 Spring 框架中⽤到了哪些设计模式?工厂模式单例模式1.饿汉式,线程安全2.懒汉式,线程不安全3.懒汉式,线程安全4.双重检查锁(DCL, 即 double-checked locking)5.静态内部类6.枚举单例 代理模…

AI 文字转语音工具以及它们的官网收集(值得收藏)

目前比较成熟的 AI 文字转语音工具以及它们的官网: 百度语音合成 (https://ai.baidu.com/tech/speech/tts): 百度语音合成是百度 AI 推出的语音合成服务,支持多种语言和音色,可以用于语音播报、智能客服、有声阅读等场景。 阿里云…

使用Kaggle API快速下载Kaggle数据集

前言 在使用Kaggle网站下载数据集时,直接在网页上点击下载可能会很慢,甚至会出现下载失败的情况。本文将介绍如何使用Kaggle API快速下载数据集。 具体步骤 安装Kaggle API包 在终端中输入以下命令来安装Kaggle API相关的包: pip install…

对 CSS 工程化的理解

CSS 工程化是为了解决以下问题: 宏观设计:CSS 代码如何组织、如何拆分、模块结构怎样设计?编码优化:怎样写出更好的 CSS?构建:如何处理我的 CSS,才能让它的打包结果最优?可维护性&a…

【计算机网络】第 11、12 问:流量控制和可靠传输机制有哪些?

目录 正文流量控制的基本方法停止-等待流量控制基本原理滑动窗口流量控制基本原理 可靠传输机制1. 停止-等待协议2. 后退 N 帧协议(GBN)3. 选择重传协议(SR) 正文 流量控制涉及对链路上的帧的发送速率的控制,以使接收…

哪些开放式耳机平价又好用的?五款超平价品牌推荐深度测评分享!

在当今快节奏的生活中,高品质的音频设备已成为放松身心的重要途径之一。开放式耳机,凭借其出色的音频表现和舒适的佩戴体验,正逐渐成为音乐爱好者的新选择。它们特有的开放设计不仅减轻了耳罩带来的压迫感,还使得用户仿佛置身于音…

四种常用限流算法、固定窗口限流算法、滑动窗口限流算法、漏桶限流算法和令牌桶限流算法

什么是限流? 限流可以被视为服务降级的一种形式,其核心目标是通过控制输入和输出流量来保护系统。通常,一个系统的处理能力是可以预估的,为了确保系统的稳定运行,当流量达到预定的阈值时,必须采取措施限制进…

vue中使用jsmind生成脑图

项目部分参数&#xff1a; vue&#xff1a;2.6.10 node:16.20.0 1、使用命令行安装jsmind&#xff1a; npm i jsmind -S 2、在文件中引入jsmind&#xff0c;并编写渲染jsmind的代码&#xff1a;&#xff1a; <template><!-- jsmind容器 --><divid"jsmi…

C#_泛型_委托

文章目录 泛型泛型的使用泛型的约束委托委托的实例化多播委托委托的调用内置委托类型委托练习泛型委托Lambda表达式(进阶)上期习题答案本期习题 泛型 泛型&#xff08;Generic&#xff09; 是一种规范&#xff0c;它允许我们使用占位符来定义类和方法&#xff0c;编译器会在编…

VLAN实验记录---对抗遗忘

sw1的接口6应该调成混杂模式&#xff0c;因为pc2,4,5,6的pvid各不相同而网段相同&#xff0c;所以往上去路由时应该剥离标记&#xff08;VLAN里面是标记而不是标签&#xff09;出去&#xff0c;这样 路由器上的物理接口用来管理不带标记的流量&#xff0c;而vlan2流量的往上打上…

git的使用日常习惯规范与一些特殊操作

git的使用日常习惯规范与一些特殊操作 操作习惯规范创建本地新分支&#xff0c;推送新分支到云端仓库1.创建一个本地的login分支2.创建新分支后切换到新分支3.推送新分支到云端 git的特殊操作撤回commit&#xff08;取消提交到本地版本库的动作&#xff0c;本地工作区写的代码不…

【LVGL-字库应用】

LVGL-中文字库应用 ■ LVGL-内部字库■ LVGL 内部字库的使用流程&#xff1a; ■ LVGL-自定义字库■ 方法一&#xff1a;C 语言数组&#xff08;内部读取&#xff09;-在线转换工具■ 方法二&#xff1a;C 语言数组&#xff08;内部读取&#xff09;-利用离线字体转换软件&…

Java学习记录第十三天

面向对象编程 核心思想就是OOP&#xff08;面向对象编程&#xff09; 面向过程&面向对象 面向过程思想 步骤清晰简单&#xff0c;第一步做什么&#xff0c;第二步做什么... 面对过程适合处理一些较为简单的问题 面向对象思想 物以类聚&#xff0c;分类的思维模式&…