机器学习之KNN、Python实现

news2024/10/2 14:29:32

文章目录

  • 一、前言
  • 二、KNN
    • (1)简介
    • (2)思想: "近朱者赤近墨者黑"
    • (3)算法实现流程
    • (4)k值得选定
      • 1. k值得作用
      • 2. `交叉验证`选取 k值
  • 三、KNN基于sklearn实现
    • (1.)准备数据
    • (2.)k值得选择
    • (3.)进行模型搭建
    • (4.)模型使用
    • (5.)模型问题
  • 四、针对上面问题进行knn封装
    • (1)数据处理
      • 均值方差归一化
      • 最小-最大归一化
      • 数据处理
    • (2)不掉包实现完整代码
    • (3)KNN使用KD树加速
  • 五、完整代码
    • (1)调包实现完整代码
    • (2)不掉包实现完整代码
  • 六、KNN的优缺点
  • 七、参考文献

一、前言

knn虽然基础,但是应用还是很多的。性价比不错。
在知乎上看到一句话:
KNN是新来的小弟选一个山头, K-means是群龙无首小弟们选举出新的山头(可以多个)

很形象的解释了,knn与k-means的区别

重要元素
KNN算法有K值的选择距离计算决策方法等三个基本要素

二、KNN

(1)简介

  1. KNN是一种基于实例的无参学习算法,通过计算新数据与训练集中所有样本之间的距离,并选取k个最近邻来进行分类回归预测。在分类问题中,KNN算法采用多数投票的方法进行决策;在回归问题中,KNN算法采用平均值法进行预测。
  2. 因此,KNN算法的目标是将新数据点分配给与其距离最近训练数据点所属的类别或者预测其对应的数值,而不是最小化某个损失函数。也正因为如此,KNN算法适用于许多非线性非参数化的问题,但也具有一定的局限性,例如在处理高维度数据时,KNN算法的时间和空间复杂度会随着样本数量的增加呈指数级增长,导致效率低下。

(2)思想: “近朱者赤近墨者黑”

KNN(K-Nearest Neighbors)算法的核心思想是基于样本间的距离来进行分类或回归。在分类问题中,给定一个新的样本,KNN算法会在训练数据集中找到k个距离该样本最近的样本,然后根据这k个样本所属类别的多数投票结果来确定该样本的类别。在回归问题中,KNN算法同样寻找k个距离该样本最近的样本,然后取它们的平均值作为该样本的回归预测结果

(3)算法实现流程

  1. 准备数据:将已知类别的数据集按照一定规则进行划分,通常把其中的一部分作为训练集,另一部分作为测试集。

  2. 计算距离:对于每一个待分类的样本,计算它与训练集中所有样本之间的距离。通常使用欧氏距离(Euclidean Distance)或曼哈顿距离(Manhattan Distance)等度量方式来进行距离计算。
    常见的欧式距离

d(p, q) = sqrt((p1 - q1)^2 + (p2 - q2)^2 + ... + (pn - qn)^2)

其中,p1, p2, …, pn和q1, q2, …, qn分别表示向量p和向量q在各自的第1个维度到第n个维度上的坐标值。sqrt表示计算平方根。

  1. 选择K值:根据预设的K值,选取距离该样本最近的K个样本

  2. 进行预测:根据K个最近的样本的类别,通过投票决定该样本所属的类别。通常采用多数表决(Majority Vote)的方式,即选择出现次数最多的类别作为预测结果。

  3. 评估模型:使用测试集对模型进行评估,通常使用错误率(Error Rate)或精确度(Accuracy)等指标来衡量模型的性能。

(4)k值得选定

k值的选定,是一件很重要的事情,直接影响了模型的表现能力。

1. k值得作用

k值是KNN算法的一个超参数,K的含义即参考”邻居“标签值的个数。 有个反直觉的现象,K取值较小时,相当于我们在较小的领域内训练样本对实例进行预测。这时,算法的近似误差(Approximate Error)会比较小,因为只有与输入实例相近训练样本才会对预测结果起作用。预测的结果对紧邻点十分敏感,容易导致过拟合同理K取值较大时,模型复杂度低,训练误差会增大,泛化能力有一定的提高,容易欠拟合。

2. 交叉验证选取 k值

在KNN算法中,选择合适的K值非常重要,直接影响到模型的分类准确率。为了确定最优的K值,可以使用交叉验证(Cross Validation)方法进行。常用的交叉验证方法有K折交叉验证留一法交叉验证

以K折交叉验证为例,具体实现步骤如下:

  1. 原始数据集分成K个子集,将其中一个子集作为测试集,剩余的K-1个子集作为训练集

  2. K-1个训练集运用KNN算法,得到不同分类模型,并将这些模型对测试集进行分类

  3. 计算每个模型的分类准确率,并计算它们的平均值作为该K值下的分类准确率。

  4. 重复以上步骤,直到尝试完所有可能的K值为止。

  5. 根据得到的分类准确率,选择最优的K值作为KNN算法的参数。

需要注意的是,在实际应用中,一般将样本量较小的数据集划分为更少的折数,而将样本量较大的数据集划分为更多的折数,以提高模型的泛化能力准确性。同时,还需要考虑到模型的计算效率时间成本等因素,选择一个合适的K值。

三、KNN基于sklearn实现

基于上面的算法步骤流程进行逐步实现

(1.)准备数据

使用约会数据进行简单处理
在这里插入图片描述

(2.)k值得选择

这里我们使用 交叉验证方法:代码如下

#todo 加载数据
    data = pd.read_csv('knnData.csv')
    x = data.iloc[:,0:3]
    y = data.iloc[:,-1:]
    print(x)
    k_accuracy = []
    for i in range(1,31):
        knn = KNeighborsClassifier(n_neighbors=i)
        socres = cross_val_score(knn,x,y,cv=10,scoring='accuracy')
        k_accuracy.append(socres.mean())
        '''
        在进行交叉验证时,我们会对模型在不同的“折”上的表现进行评估,并计算所有“折”的得分的平均值。因此,这里使用scores.mean()将模型在每个“折”上的得分求平均,得到一个k值对应的平均准确率。
        cross_val_score函数默认返回每个“折”上的得分(即一个长度为10的数组),而这里我们需要的是该k值下的平均准确率,因此使用scores.mean()将数组中的得分求平均。
        具体来说,scores.mean()计算的是模型在10折交叉验证中所有“折”上得分的平均值,作为当前k值的平均准确率。  
        '''
    plt.plot(range(1,31),k_accuracy)
    plt.xlabel('Value of k for KNN')
    plt.ylabel('Cross-Validated Accuracy')
    plt.show()

看下效果展示

在这里插入图片描述
可以看到,当k值为18的时候,我们的模型准确率最高
因此,k值我们就设定为18

(3.)进行模型搭建

选定好 k值后就开始进行模型搭建:

data = pd.read_csv('knnData.csv')
#进行特征值的选择
x = data.iloc[:,0:3]
y = data.iloc[:,-1:]
# 创建色彩图
cmap_light = ListedColormap(['orange', 'cyan', 'cornflowerblue'])
cmap_bold = ListedColormap(['darkorange', 'c', 'darkblue'])

X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.3)

'''
weights(权重):最普遍的 KNN 算法无论距离如何,权重都一样,但有时候我们想搞点特殊化,比如距离更近的点让它更加重要。这时候就需要 weight 这个参数了,这个参数有三个可选参数的值,决定了如何分配权重。参数选项如下:
• ‘uniform’:不管远近权重都一样,就是最普通的 KNN 算法的形式。
• ‘distance’:权重和距离成反比,距离预测目标越近具有越高的权重。
• 自定义函数:自定义一个函数,根据输入的坐标值返回对应的权重,达到自定义权重的目的。
'''
#todo 分别在两种权重情况下进行对比

for weights in ["uniform","distance"]:

    #todo 第一步:创建knn分类器
    knn = neighbors.KNeighborsClassifier(n_neighbors = 18,weights=weights)
    knn.fit(X_train,y_train)

    #todo 第二步: 用测试集进行预测,并计算准确率
    y_pred = knn.predict(X_test)
    print(y_pred)
    # accuracy = np.mean(y_pred == y_test)

(4.)模型使用

检验下模型效果:

  #使用模型预测新的数据点
    X_new = np.array([[38344, 3.0, 0.1343], [3436, 3.0, 4.0], [7, 9.0, 6.0]])
    y_new = knn.predict(X_new)  # 预测新的数据点类别

    print(f"New data point {X_new[0]} belongs to class {[y_new[0]]}")
    print(f"New data point {X_new[1]} belongs to class {[y_new[1]]}")
    print(f"New data point {X_new[2]} belongs to class {[y_new[2]]}")

打印结果:

在这里插入图片描述
哈哈效果一般啊:

(5.)模型问题

  1. 对于数据的第一列没用进行归一化操作,可以看到两种不同
  2. 对于标签值没有进行数字化处理
  3. 对于大型数据集处理起来太慢

四、针对上面问题进行knn封装

(1)数据处理

目的:对数据进行归一化是为了将不同特征数值范围统一到相同的区间内,以避免某些特征对模型训练的影响过大。
好处:归一化可以提高模型的收敛速度和精度,并且有助于提高算法的鲁棒性和泛化能力
方法:常见的归一化方法包括最小-最大归一化均值方差归一化等。

均值方差归一化

均值方差归一化(Mean-Variance Normalization)是一种数据归一化方法,也称为标准化(Standardization)。它通过对原始数据进行线性变换,使其均值为0,标准差为1。

具体而言,假设原始数据集为 X = x 1 , x 2 , . . . , x n X={x_1, x_2, ..., x_n} X=x1,x2,...,xn,其中 x i x_i xi是第 i i i个样本的特征向量。则均值方差归一化的公式如下:

x ˉ = 1 n ∑ i = 1 n x i \bar{x}=\frac{1}{n}\sum_{i=1}^n x_i xˉ=n1i=1nxi

σ = 1 n ∑ i = 1 n ( x i − x ˉ ) 2 \sigma=\sqrt{\frac{1}{n}\sum_{i=1}^n(x_i-\bar{x})^2} σ=n1i=1n(xixˉ)2

x i ′ = x i − x ˉ σ x'_i =\frac{x_i - \bar{x}}{\sigma} xi=σxixˉ

其中, x ˉ \bar{x} xˉ表示样本特征的平均值, σ \sigma σ表示样本特征的标准差。对每一个特征都执行以上操作,即可实现均值方差归一化。

均值方差归一化可以使得数据分布更加接近标准正态分布,从而提高模型的准确性和稳定性。同时,该方法也可以避免由于不同特征之间数量级不同而导致的误差或偏差。常见的机器学习算法如神经网络、支持向量机等都需要进行均值方差归一化处理

代码可以使用:

import numpy as np

def mean_variance_normalize(X):
    """
    均值方差归一化
    :param X: ndarray类型的数据集
    :return: 归一化后的数据集
    """
    X_norm = (X - np.mean(X, axis=0)) / np.std(X, axis=0)
    return X_norm

其中,X是一个ndarray类型的数据集,np.mean(X, axis=0)np.std(X, axis=0)分别计算了每个特征的均值标准差。在代码中,我们使用了numpy库来进行矩阵运算,从而提高计算效率。
例如

#创建一个3*4的数据集
X = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

最小-最大归一化

最小-最大归一化(Min-Max Normalization),又称离差标准化,是一种常用的数据归一化方法。它将原始数据通过线性变换映射到[0,1]区间内。

具体而言,假设原始数据集为 X = x 1 , x 2 , . . . , x n X={x_1, x_2, ..., x_n} X=x1,x2,...,xn,其中 x i x_i xi是第 i i i个样本的特征向量。则最小-最大归一化的公式如下:

x i ′ = x i − min ⁡ ( X ) max ⁡ ( X ) − min ⁡ ( X ) x'_i =\frac{x_i - \min(X)}{\max(X)-\min(X)} xi=max(X)min(X)ximin(X)

其中, min ⁡ ( X ) \min(X) min(X)表示样本特征的最小值, max ⁡ ( X ) \max(X) max(X)表示样本特征的最大值。对每一个特征都执行以上操作,即可实现最小-最大归一化。

最小-最大归一化可以使得数据分布更加均匀,避免了由于不同特征之间数量级不同而导致的误差或偏差。该方法适用于数据的最大值最小值已知的情况,并且对异常值敏感。在某些需要保留数据分布形态的场景下,最小-最大归一化不太适用,比如一些机器学习算法要求输入数据应该服从正态分布。

代码实现:

def min_max_normalize(X):
    """
    最小-最大归一化
    :param X: ndarray类型的数据集
    :return: 归一化后的数据集
    """
    X_norm = (X - np.min(X, axis=0)) / (np.max(X, axis=0) - np.min(X, axis=0))
    return X_norm

其中,X是一个ndarray类型的数据集,np.min(X, axis=0)np.max(X, axis=0)分别计算了每个特征的最小值最大值。在代码中,我们使用了numpy库来进行矩阵运算,从而提高计算效率

数据处理

(2)不掉包实现完整代码

(3)KNN使用KD树加速

五、完整代码

(1)调包实现完整代码

使用sklearn进行knn实现

(2)不掉包实现完整代码

六、KNN的优缺点

七、参考文献

[1].https://zhuanlan.zhihu.com/p/45453761
[2].https://www.zhihu.com/question/40456656
[3].https://zhuanlan.zhihu.com/p/122195108
[4].https://blog.csdn.net/codedz/article/details/108862498
[5].https://blog.csdn.net/c406495762/article/details/75172850

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

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

相关文章

苹果XR头显简史:现实困境与未来预期

近几个月来,有关苹果MR头显的消息层出不穷,机构分析师大多认为6月份的WWDC23将会亮相。作为全新品类,苹果AR/VR备受期待的同时也有一些市场顾虑,例如因AR/VR产品成熟度问题,现阶段推出MR头显也饱受争议,甚至…

单例模式与多线程

文章目录 一、 简介二、详细介绍1. 立即加载/饿汉模式2. 延迟加载/懒汉模式3. 使用静态内置类实现单例模式4. 序列化和反序列化的单例模式5. 使用static代码块实现单例模式6. 使用enum枚举数据类型实现单例模式 一、 简介 在标准的23个设计模式中,单例模式在应用中…

传染病学模型 | SIR 、SEIR传染病学模型

文章目录 SIR传染病学模型SEIR传染病学模型参考资料SIR传染病学模型 SIR模型是一种流行病学模型,用于描述传染病在人群中的传播过程。SIR模型将人群分为三个类别:易感者(Susceptible)、感染者(Infectious)和康复者(Recovered)。三个类别之间的转移可以用以下三个微分方…

二、IOC容器(1)

一、IOC操作Bean管理 1.什么是Bean管理? Spring创建对象Spring注入属性Bean管理是2个操作 2.Bean管理操作有两种方式 基于xml配置文件方式实现基于注解方式实现 二、IOC操作Bean管理(基于xml方式) 1.基于xml方式创建对象 使用bean标签&…

new与delete用法详解与底层原理,operator new与operator delete函数,定位new与内存泄漏介绍等

tips 其实进程运行起来或者说程序运行起来都是去执行函数,任务就是不断的去执行函数。C的入口就是main函数,然后在这个函数当中可能碰到程序某些调用其他函数的语句就去调用其他函数。在全局的区域可以去创建变量,定义函数,但就是…

数据结构-栈,队列

栈,队列 1 知识框架2 栈2.1 顺序栈2.2 链式栈 3 队列3.1 顺序队列3.2 循环队列3.3 链式队列 4 数组4.1 二维数组4.2 特殊数组的压缩存储 1 知识框架 2 栈 定义:只允许在一端进行插入或删除得到线性表 栈的数学性质:n个不同元素进栈&#xff…

phpWord使用模板填充数据:包含表格及嵌套表格(多个表格/循环表格)

参考文档 模板处理 基础使用 安装过程省略,首先加载模板: $templateProcessor new TemplateProcessor(ROOT_PATH . uploads/template/自动生成模板.docx); 完整保存流程 首先,要进行测试,起码能够写一个完整的demo,以下是我测…

实验三---面向对象分析与设计——UML用例图与活动图

一、实验目的: 掌握面向对象分析中用例建模的基本思想,学会识别参与者和用例,掌握UML用例图的绘制方法,学会编写用例说明;了解活动图的作用和组成元素,掌握UML活动图的绘制方法,学会使用活动图来…

秒懂算法 | KMP算法(Java描述)

Knuth-Morris-Pratt 算法(简称 KMP)是由高德纳(Donald Ervin Knuth)和沃恩普拉特在1974年构思,同年詹姆斯H莫里斯也独立地设计出该算法,最终三人于1977年联合发表。该算法较Brute-Force算法有较大改进&…

门电路OD门

漏极开路输出的门电路(OD门) 为了满足输出电平的变换,输出大负载电流,以及实现“线与”功能,将CMOS门电路的输出级做成漏极开路的形式,称为漏极开路输出的门电路,简称OD(Open&#x…

【JVM】1. JVM与Java体系结构

文章目录 1.1. 前言🍉1.2. 参考书目🍉1.3. Java及JVM简介🍉1.4. Java发展的重大事件🍉1.5. 虚拟机与Java虚拟机🍉1.6. JVM的整体结构🍉1.7. Java代码执行流程🍉1.8. JVM的架构模型🍉…

4. QT中的鼠标键盘事件 --- 鼠标拖拽案例

1. 说明 在QT的控件或者窗口当中,如果对于当前鼠标或者键盘的功能需要自己定义,可以重写父类当中对应虚函数,主要包括以下几个: //键盘按键按下 virtual void keyPressEvent(QKeyEvent *event); //键盘按键抬起 virtual void ke…

为什么C++这么复杂还不被淘汰?

C是一门广泛使用的编程语言,主要用于系统和应用程序的开发。尽管C具有一些复杂的语法和概念,但它仍然是编程界的重量级选手,在编程语言排行榜中一直位居前列。为什么C这么复杂还不被淘汰呢? C有以下优势 1、C具有高性能 C是一门编…

unity进阶学习笔记:photonServer测试

photonServer是由photon发布的一个网络框架,其封装了UDP和TCP通信机制让用户可以直接调用API实现网络游戏通信 1 photonServer下载安装 进入Photon官网的SDK选项,选择下载Server。目前Server版本已经更新到v5,这里我为了和教程保持一致下载…

Unittest接口测试生成报告和日志方法

HTML报告 直接把HTMLTestRunner.py放入工程目录即可报告脚本封装 #HTNL格式报告now datetime.datetime.now().strftime(%Y-%m-%d_%H_%M_%S)htmlreport reportpath "/" now r"result.html"print("测试报告生成地址:%s"% htmlre…

Revit干货 | 系统族、内建族、可载入族一次性搞清楚!

对于使用人数较多的revit软件,其中的许多概念与我们常用的CAD完全不同,以至于让许多工程师觉得revit软件有点高深莫测,不可琢磨,从而有了抗拒心理。 Revit软件中的重要概念: “族”是revit软件中的很重要也很基本的概念…

程序的各种段以及堆栈相关问题

C中一般有三种变量: 局部变量全局变量静态变量 C中一般有五个内存段: 代码段 也叫文本段,包含frequently executed code通常是只读的(未了避免程序被错误改写)代码段是不包含程序变量(如局部变量、全局变…

【数据结构】带头双向链表,真正的六边形战士

文章目录 概要整体架构流程小结 概要 *数据结构中的链表在实际开发中应用非常广泛,但写一个链表并不是一件简单的事情。链表有八种结构,对于刚入门的新手来说,往往会先经历单链表的折磨。 而今天我要讲的带头双向链表非常适合新手学习&#…

C++6.类和对象(下)

1.友元函数,一般现在类的最上面。 2.函数的参数中,如果不改变,尽量加上const修饰。 3.对于自定义类型,使用运算符进行操作基本上都要用运算符重载,但是有些运算符重载会默认自动生成。 4.初始化列表,是成…

【wpf】列表类,用相对源时,如何绑定到子项

前言 在之前的一篇文章 :《【wpf】深度解析,Binding是如何寻找数据源的》https://blog.csdn.net/songhuangong123/article/details/126195727#:~:text%E3%80%90wpf%E3%80%91%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90%EF%BC%8CBinding%E6%98%AF%E5%A6%82%E4…