草庐IT

【机器学习实战】K- 近邻算法(KNN算法)

玄澈_ 2023-04-09 原文


K-近邻算法

一、概述

K-近邻算法,又称为 KNN 算法,是数据挖掘技术中原理最简单的算法。

KNN 的工作原理:给定一个已知类别标签的数据训练集,输入没有标签的新数据后,在训练数据集中找到与新数据最临近的 K 个实例。如果这 K 个实例的多数属于某个类别,那么新数据就属于这个类别。

简单理解为: 由那些离 X 最近的 K 个点来投票决定 X 归为哪一类


举个例子,可以用 KNN 算法来分类一部电影是爱情片还是动作片(利用打架镜头和接吻镜头来做大致判断)

这个表就是我们已有的数据集合,也就是训练样本集。

这个数据集有两个特征 - 打斗镜头数和亲吻镜头数。
除此之外,我们还知道每部电影的所属类型,即分类样本

那么这样子我们该如何运用KNN算法来判断表中的新电影所属的电影类别呢?如下图所示

 从散点图中我们可以分析大致推断,这个电影很有可能是爱情片,因为它的距离和已知的三个爱情片更近一点。

KNN 算法是利用什么方法进行判断的呢?
没错,就是距离度量 

在二维平面中可以使用高中就学过的距离计算公式

如果是多个特征拓展到 N维空间 的话, 我们可以使用欧氏距离(也称欧几里得度量),如下所示:


通过计算可以得到训练集中所有的电影和新电影之间的距离,如下图所示

 通过表中的计算结果,我们可以知道绿点标记的电影到爱情片《后来的我们》距离最近,为 29.1.但如果只靠这样来判断的话,这个算法应该叫 最近邻算法。

KNN算法的步骤如下(一般 k ≤ 20)

  1. 计算已知类别数据集中的点与当前点之间的距离
  2. 按照距离递增次序排序
  3. 选取与当前距离最小的k个点
  4. 确定前k个点所在类别的出现频率
  5. 返回前k个点出现频率最高的类别作为当前点的预测类别

通过统计,当 k = 4 的时候,这四部电影的类别统计为 爱情片 :动作片 = 3 : 1 ,出现频率最高的类别是爱情片,所以在 k = 4 的时候,新电影的类别为 爱情片


KNN的python实现

1.1构建已经分类好的原始数据集

import pandas as pd
rowdata={'电影名称':['无问西东','后来的我们','前任3','红海行动','唐人街探案','战狼2'],
         '打斗镜头':[1,5,12,108,112,115],
         '接吻镜头':[101,89,97,5,9,8],
         '电影类型':['爱情片','爱情片','爱情片','动作片','动作片','动作片']}
movie_data = pd.DataFrame(rowdata)
movie_data


 1.2.算已知类别数据集中的点与当前点之间的距离

new_data = [24, 67]
dist = list((((movie_data.iloc[:6, 1: 3] - new_data)**2).sum(1))**0.5)  * 对行求和

1.3将距离升序排列,然后选取距离最小的k个点

k = 4
dist_l = pd.DataFrame({'dist': dist, 'labels': (movie_data.iloc[:6, 3])})
dr = dist_l.sort_values(by = 'dist')[: k]
dr

1.4 确定前k个点所在类别的出现频率

re = dr.loc[:, 'labels'].value_counts()
re.index[0]
result = []
result.append(re.index[0])
result

封装函数

import pandas as pd
"""
函数功能:KNN分类器
参数说明:
    inX:需要预测的数据集
    dataSet:已知分类标签的数据集(训练集)
    k:k-近邻算法参数,选择距离最小的k个点
返回:
result:分类结果
"""
def classify0(inX, dataSet, k):
    result = []
    dist = list((((dataSet.iloc[:6, 1: 3] - inX)**2).sum(1))**0.5)
    dist_l = pd.DataFrame({'dist': dist, 'labels': (dataSet.iloc[:6, 3])})
    dr = dist_l.sort_values(by = 'dist')[: k]
    re = dr.loc[:, 'labels'].value_counts()
    result.append(re.index[0])
    return result

小结

分类器并不会得到百分比正确的结果,除此之外,分类器的性能也会受到很多因素的影响,比如k的取值就会在很大程度上影响了分类器的预测结果,还有分类器的设置、原始数据集等等。
为了测试分类效果,我们将原始数据集分为两部分一部分用来训练算法(称为训练集),一部分用来测试算法的准确率(称为测试集)


k-近邻算法之约会网站配对效果判定

海伦一直使用在线约会网站寻找适合自己的约会对象,尽管约会网站会推荐不同的人选,但她并不是每一个都喜欢,经过一番总结,她发现曾经交往的对象可以分为三类:
1.不喜欢的人
2.魅力一般的人
3.极具魅力得人
海伦收集约会数据已经有了一段时间,她把这些数据存放在文本文件datingTestSet.txt中,其中各字段分别为:

  1. 每年飞行常客里程
  2. 玩游戏视频所占时间比
  3. 每周消费冰淇淋公升数

1.准备数据

datingTest = pd.read_table('datingTestSet.txt',header=None)
datingTest.head()
datingTest.shape
datingTest.info()

2. 分析数据

%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt

# 将不同标签用颜色区分
Colors = []
for i in range(datingTest.shape[0]):
    m = datingTest.iloc[i,-1]
    if m =='didntLike':
        Colors.append('black')
    if m =='smallDoses':
        Colors.append('orange')
    if m =='largeDoses':
        Colors.append('red')

# 绘制两两之间的散点图
plt.rcParams['font.sans-serif']=['Simhei'] #图中字体设置为黑体
pl=plt.figure(figsize=(12,8))
fig1=pl.add_subplot(221)
plt.scatter(datingTest.iloc[:,1],datingTest.iloc[:,2],marker='.',c=Colors)
plt.xlabel('玩游戏视频所占时间比')
plt.ylabel('每周消费冰淇淋公升数')
fig2=pl.add_subplot(222)
plt.scatter(datingTest.iloc[:,0],datingTest.iloc[:,1],marker='.',c=Colors)
plt.xlabel('每年飞行常客里程')
plt.ylabel('玩游戏视频所占时间比')

fig3=pl.add_subplot(223)
plt.scatter(datingTest.iloc[:,0],datingTest.iloc[:,2],marker='.',c=Colors)
plt.xlabel('每年飞行常客里程')
plt.ylabel('每周消费冰淇淋公升数')
plt.show()


 3. 数据归一化

 我们很容易发现,上面公式中差值最大的属性对计算结果的影响最大,也就是说每年飞行常客里程对计算结果的影响远远大于其他两个特征,原因仅仅是因为它的数值比较大,但是在海伦看来这三个特征是同等重要的,所以接下来我们要进行数值归一化的处理,使得这三个特征的权重相等。
数据归一化的处理方法有很多种,比如0-1标准化、Z-score标准化、Sigmoid压缩法等等

在这里我们使用最简单的0-1标准化,公式如下:

数据处理中0-1规范化和标准化 - 知乎 (01标准化)

def minmax(dataSet):
    minDf = dataSet.min()
    maxDf = dataSet.max()
    normSet = (dataSet - minDf)/(maxDf - minDf)
    return normSet

将我们的数据集带入函数,进行归一化处理

datingT = pd.concat([minmax(datingTest.iloc[:, :3]), datingTest.iloc[:,3]], axis=1)
datingT.head()

4. 划分训练集和测试集

通常来说,我们只提供已有数据的90%作为训练样本来训练模型,其余10%的数据用来测试模型的准确性

"""
函数功能:切分训练集和数据集
参数说明
    dataSet:原始数据集
    rate:训练集所占的比例
返回:切分好的训练集和数据集
"""
def randSplit(dataSet, rate = 0.9):
    n = dataSet.shape[0]
    m = int(n * rate)
    train = dataSet.iloc[:m, :]
    test = dataSet.iloc[m: ,:]
    test.index = range(test.shape[0])
    return train, test

train, test = randSplit(datingT)
train
test

5. 分类器针对于约会网站的测试代码

上面我们已经将原始数据进行归一化处理然后也切分了训练集和测试集,所以我们的函数的输出参数就可以是 traintest、和**k** (选择的距离最小的k个点)

"""
函数功能:KNN 算法分类器
参数说明:
    train:训练集
    test:测试集
    k:KNN参数,即距离最小的k个点
返回:预测好分类的测试集
"""
def datingClass(train, test, k):
    n = train.shape[0] - 1
    m = test.shape[0]
    result = []
    for i in range(m):
        dist = list((((train.iloc[:6, 1: 3] - test.iloc[1, :n])**2).sum(1))**5)
        dist_l = pd.DataFrame({'dist':dist, 'labels':(train.iloc[:, n])})
        dr = dist_l.sort_values(by = 'dist')[: k]
        re = dist.loc[:, 'labels'].value_counts()
        result.append(re.index[0])
    result = pd.Series(result)
    test['predict'] = result
    acc = (test.iloc[:,-1] == test.iloc[:, -2]).mean()
    print(f'模型预测准确率为{acc}')
    return test

最后,测试上述代码能否正常运行,使用上面生成的测试集和训练集导入分类器函数中,然后执行并查看分类结果

datingClass(train, test, 5)


 总结

k近邻
算法功能分类(核心),回归
算法类型有监督学习 - 惰性学习,距离类模型
数据输入包含数据标签 y, 且特征空间中至少包含k 个训练样本 (k ≥ 1)
特征空间中各个特征的量纲需统一,若不统一则需要进行归一化处理
自定义的超参数 k (k ≥ 1)
模型输出在KNN分类中,输出是标签中的某个类别
在KNN回归中,输出是对象的属性值,该值是距离输入的数据最近的k个训练样本标签的平均值

1.优点

  • 简单好用,容易理解,精度高,理论成熟,即可以用来做分类也可以用来做回归
  • 可用于数值型数据和离散型数据
  • 无数据输入假定
  • 适合对稀有事件进行分类

2.缺点

  • 计算复杂性高;空间复杂性高
  • 计算量太大,所以一般数值很大的时候不用这个,但是单个样本又不能太少,否则容易发生误分
  • 样本不平衡问题(即某些类别的样本数量很多,某些类别的样本数量很少)
  • 可理解性比较差,无法给出数据的内在含义

有关【机器学习实战】K- 近邻算法(KNN算法)的更多相关文章

  1. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

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

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

  3. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  4. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  5. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  6. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  7. ruby - 我的 Ruby IRC 机器人没有连接到 IRC 服务器。我究竟做错了什么? - 2

    require"socket"server="irc.rizon.net"port="6667"nick="RubyIRCBot"channel="#0x40"s=TCPSocket.open(server,port)s.print("USERTesting",0)s.print("NICK#{nick}",0)s.print("JOIN#{channel}",0)这个IRC机器人没有连接到IRC服务器,我做错了什么? 最佳答案 失败并显示此消息::irc.shakeababy.net461*USER:Notenoughparame

  8. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  9. ruby - 我如何学习 ruby​​ 的正则表达式? - 2

    如何学习ruby​​的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby​​的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/

  10. 深度学习12. CNN经典网络 VGG16 - 2

    深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG

随机推荐