机器学习(一)K近邻算法(KNN)原理剖析及python源码

news2025/1/14 2:47:54

介绍第一个机器学习算法:k-近邻算法,它非常有效而且易于掌握。首先,我们将探讨k-近邻算法KNN的基本理论,以及如何使用距离测量的方法分类物品;其次我们将使用Python从文本文件中导入并解析数据;再次,本书讨论了当存在许多数据来源时,如何避免计算距离时可能碰到的一些常见错误;最后,利用实际的例子讲解如何使用k-近邻算法改进约会网站。

概念:简单地说,k-近邻算法采用测量不同特征值之间的距离方法进行分类。

优点:精度高、对异常值不敏感、无数据输入假定

缺点:计算复杂度高、空间复杂度高;

必须要有接近实际数据的训练样本数据,所以必须保存全部数据集,若训练数据集很大则需要使用大量的存储空间。由于又必须对数据集中的每个数据计算距离值,实际使用时可能会非常耗时(优化实现:kd树)。

适用数据范围:数值型和标称型

工作原理:存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

k值的选择:交叉验证法

Kd树构造算法:给定一个目标点,搜索其最近邻。首先找到包含目标点的叶结点;然后从该叶结点出发,依次回退到父结点:不断查找与目标点最邻近的结点,当确定不可能存在更近的结点时终止。这样搜索就被限制在空间的局部区域上,效率大为提高。

案例(电影分类):首先计算未知电影与样本集中其他电影的距离,如表2-2所示。此处暂时不要关心如何计算得到这些距离值,使用Python实现电影分类应用时,会提供具体的计算方法。

在我们得到了样本集中所有电影与未知电影的距离,按照距离递增排序,可以找到k个距离最近的电影。假定k=3,则三个最靠近的电影依次是He’s Not Really into DudesBeautiful WomanCalifornia Mank-近邻算法按照距离最近的三部电影的类型,决定未知电影的类型,而这三部电影全是爱情片,因此我们判定未知电影是爱情片。

伪代码:

对未知类别属性的数据集中的每个点依次执行以下操作:

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

(2) 按照距离递增次序排序;

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

(4) 确定前k个点所在类别的出现频率;

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

Python3实现完整代码:

import pandas as pd
from numpy import *
import operator
import numpy as np


def knn_classify(inX, data_set, labels, k):  # KNN算法实现
    data_set_size = data_set.shape[0]
    # 计算欧式距离
    diffMat = tile(inX, (data_set_size, 1)) - data_set  # 距离矩阵
    sqDiffMat = diffMat ** 2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances ** 0.5

    # 距离从小到大排序
    sortedDistIndicies = distances.argsort()
    # 获取前k个距离最小元素所在分类,计算各分类发生频率
    class_count = {}
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        class_count[voteIlabel] = class_count.get(voteIlabel, 0) + 1
    # 发生频率从大到小排序
    sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
    return sorted_class_count[0][0]  # 返回频率最高的标签作为最终分类


if __name__ == '__main__':
    # 1、准备数据
    group = np.array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
    labels = ['A', 'A', 'B', 'B']
    import matplotlib.pyplot as plt

    plt.scatter([g[0] for g in group], [g[1] for g in group], marker='.', color='black', s=20)
    for i in range(group.shape[0]):
        plt.text(group[i][0], group[i][1], labels[i])  # 加标签
    plt.show()
    # 2、KNN算法实现
    k = 3
    knn_classify([0, 0], group, labels, k)
    # 3、算法测试(以相亲约会数据为例)
    data = pd.read_table("E:\datingTestSet.txt", header=None, sep="\t")
    data.columns = ["里程数/年", "游戏时间占比", "冰淇淋公升数/周", "匹配类型"]
    datingDataMat = data[["里程数/年", "游戏时间占比", "冰淇淋公升数/周"]].to_numpy()
    datingLabels = data[["匹配类型"]].to_numpy()
    datingLabels = [d[0] for d in datingLabels]  # 去列表并数值化
    datingLabels = [1 if d == 'didntLike' else d for d in datingLabels]
    datingLabels = [2 if d == 'smallDoses' else d for d in datingLabels]
    datingLabels = [3 if d == 'largeDoses' else d for d in datingLabels]
    # 3-1、画图统计描述
    import matplotlib.pyplot as plt
    # 游戏时间占比和冰淇淋公升数
    plt.scatter(datingDataMat[:, 1], datingDataMat[:, 2], 15 * np.array(datingLabels), 15 * np.array(datingLabels))
    plt.show()
    # 里程数和游戏时间占比
    plt.scatter(datingDataMat[:, 0], datingDataMat[:, 1], 15 * np.array(datingLabels), 15 * np.array(datingLabels))
    plt.show()
    # 3-2、数值归一化
    minVals = datingDataMat.min(0)
    maxVals = datingDataMat.max(0)
    ranges = maxVals - minVals
    m = datingDataMat.shape[0]  # 行数
    norm_data_set = datingDataMat - np.tile(minVals, (m, 1))  # tile是将minVals的行重复m次,列重复1次
    norm_data_set = norm_data_set / np.tile(ranges, (m, 1))
    # 3-3、测试验证
    hoRatio = 0.10  # hold out 10%
    m = norm_data_set.shape[0]
    numTestVecs = int(m * hoRatio)  # 验证集数量
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = knn_classify(norm_data_set[i, :], norm_data_set[numTestVecs:m, :], datingLabels[numTestVecs:m], 3)
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))
        if classifierResult != datingLabels[i]:
            errorCount += 1.0
    print("error count: ", errorCount)
    print("the total error rate is: %f" % (errorCount / float(numTestVecs)))
    # 4、算法使用
    result_list = ['not at all', 'in small doses', 'in large doses']
    ff_miles = float(input("frequent flier miles earned per year?"))
    percent_tats = float(input("percentage of time spent playing video games?"))
    ice_cream = float(input("liters of ice cream consumed per year?"))
    in_array = np.array([ff_miles, percent_tats, ice_cream])
    classifier_result = knn_classify((in_array-minVals) / ranges, norm_data_set, datingLabels, 3)
    print("You will probably like this person: ", result_list[classifier_result-1])

备注:

datingTestSet数据集直接去源码地址下载www.manning.com/MachineLearninginAction

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】你知道为什么在写C++代码之前要在开头写上using namespace std吗?

👦个人主页:Weraphael ✍🏻作者简介:目前学习C和算法 ✈️专栏:C航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞&#x1…

如何设计一个高并发系统

目录 如何理解高并发系统 1. 分而治之,横向扩展 2. 微服务拆分(系统拆分) 3. 分库分表 4. 池化技术 5. 主从分离 6. 使用缓存 7. CDN——加速静态资源访问 8. 消息队列——削锋 9. ElasticSearch 10. 降级熔断 11. 限流 12. 异步…

算法刷题总结 (八) 前缀和

算法总结8 前缀和 一、前缀和的概念1.1、什么是前缀和?1.2、常见类型1.2.1、求数组前i个数之和1.2.2、求数组的区间和 二、经典例题2.1、求数组前i个数之和560. 和为 K 的子数组 - 前缀和哈希表525. 连续数组 2.2、求数组的区间和303. 区域和检索 - 数组不可变643. …

学系统集成项目管理工程师(中项)系列06b_信息系统安全管理(下)

1. 物理安全管理 1.1. 计算机机房与设施安全 1.1.1. 计算机机房 1.1.1.1. 机房场地选择 1.1.1.2. 机房空调、降温 1.1.1.2.1. 基本温度要求 1.1.1.2.1.1. 应有必要的空调设备,使机房温度达到所需的温度要求 1.1.1.2.2. 较完备空调系统 1.1.1.2.2.1. 应有较完…

C语言——隐式转换

目录 前言 隐式转换 1.整型提升 2.算数转换 前言 这里小编给大家简单的补充一下,一些有关C语言的知识点 隐式转换 由于转换形式的不同类型转换这里一共分为整型提升和运算转换两种形式 1.整型提升 在了解整型提升之前,这里我们需要先了解一下截断…

自媒体助手软件开发需具备哪些功能?

自媒体助手软件开发需具备哪些功能? 1、多平台多账号管理。 用户可以在单独的平台上管理其他平台的账号,不需要登录多个平台,为用户减少了大量的时间,与此同时可以记忆账号和密码,提供分组管理&#xff…

【C进阶】详解预处理指令

文章目录 预定义符号#define#define定义标识符#define定义宏#define替换规则#和##带副作用的宏参数宏和函数对比#undef命令行定义 条件编译文件包含头文件被包含的方式嵌套文件包含 其他预处理指令总结 预定义符号 __FILE__ //进行编译的源文件 __LINE__ //文件当前的行号 __DA…

解码星地一体农机导航:无网作业,极致

星地一体系列农机导航最强大之处是在全国任何地方都拥有信号,即使是在偏远的戈壁滩也能作业,因为星地一体系列导航采用星地融合技术,彻底解决信号问题,通过卫星播发差分信号的服务,在中国,只要可见卫星&…

Windows下如何查看某个端口被谁占用被杀死占用进程

开发时经常遇到端口被占用的情况,这个时候我们就需要找出被占用端口的程序,然后结束它,本文为大家介绍如何查找被占用的端口。 1、打开命令窗口(以管理员身份运行) 开始—->运行—->cmd,或者是 windowR 组合键,…

Win10桌面我的电脑怎么调出来?最简单方法教学

Win10桌面我的电脑怎么调出来?有用户发现自己的电脑桌面没有我的电脑这个程序图标,每次要访问磁盘的时候,开启都非常的麻烦。那么怎么将这个图标设置到桌面显示呢?接下来我们一起来看看以下的解决方法吧。 方法一: 在开…

论文中参考文献的引用

论文中参考文献的引用 写在最前面删除特定格式的数字(带小中大括号等等)效果如下 设置参考文献格式设置编号格式设置段落格式效果 使用交叉引用去引用这些编号在需要插入参考文南引用的地方使用“交叉引用”快捷键进阶:为“交叉引用”设置快捷键 写在最前…

maven安装及配置IDEA

文章目录 下载下载完成后 解压可以得到如下的目录项 配置环境变量输入下列命令 出现 maven版本表示环境变量配置成功 配置本地仓库、镜像仓库、jdk版本配置本地仓库配置镜像仓库配置jdk版本 IDEA配置maven配置当前项目的maven配置其他项目的maven 下载 https://maven.apache.o…

威联通NAS文件共享 - 搭建SFTP服务并内网穿透实现在外远程访问

文章目录 前言1. 威联通NAS启用SFTP2. 测试局域网访问3. 内网穿透3.1 威联通安装cpolar内网穿透3.2 创建隧道3.3 测试公网远程访问 4. 配置固定公网TCP端口地址4.1 保留一个固定TCP端口地址4.2 配置固定TCP端口地址4.3 测试使用固定TCP端口地址远程连接威联通SFTP 转载自远程内…

Java web 项目 和 java 项目的区别

一、Java Web项目 和 java项目区别 1. Java Web项目是基于Java EE类的;而Java项目是基于Java应用程序的。 2. Java Web项目是网页的编码,像jsp,servlet,struts这类的,而java项目是AWT,SWING这类的编码。 3. Java Web项目中的JAVA文件是tomcat…

【CocosCreator入门】CocosCreator组件 | Layout(布局)组件

Cocos Creator 是一款流行的游戏开发引擎,具有丰富的组件和工具,其中的Layout组件是一种用于实现节点自适应布局的重要组件。它可以根据不同的布局方式,自动调整子节点的位置和大小,从而实现节点的自适应布局。 目录 一、组件介绍…

准备换工作的看过来~

大家好,最近有不少小伙伴在后台留言,得准备面试了,又不知道从何下手!为了帮大家节约时间,特意准备了一份面试相关的资料,内容非常的全面,真的可以好好补一补,希望大家在都能拿到理想…

运行时内存数据区之方法区(二)

方法区的演进细节 首先明确:只有HotSpot才有永久代。BEA JRockit、IBMJ9等来说,是不存在永久代的概念的。原则上如何实现方法区属于虚拟机实现细节,不受《]Va虚拟机规范》管束,并不要求统一。Hotspot中方法区的变化: …

Spring核心-IoC控制反转详解 (典藏版)

文章目录 1.IoC容器和Bean介绍2.Spring 中的 IoC 容器2.1 BeanFactory和ApplicationContext概述2.2 BeanFactory2.3 ApplicationContext2.4 BeanFactory vs ApplicationContext2.5 容器的初始化2.6 配置元数据2.6.1 基于XML的容器配置2.6.2 基于注解的容器配置2.6.3 基于Java类…

Junit概述和快速入门

单元测试概述 在程序中,一个单元可以是一个完整的模块,但它通常是一个单独的方法或者程序 在面向对象的编程中,一个单元通常是整个界面,例如类,但可能是单个方法 JUnit是一个java编程语言的单元测试框架 通过先为最…

教育大数据总体解决方案(4)

组件配置 对组件中的项目配置项进行管理,包括节点内容、磁盘空间等等。每一次的配置都以一个配置版本的形式进行保存,用户可选择对应版本的查看对应的配置信息。 测度 对组件内的相关服务指标以图标形式进行状态呈现。可选择相应时间段,查看对…