机器学习系列----KNN分类

目录

前言

一.KNN算法的基本原理

二.KNN分类的实现

三.总结


前言

在机器学习领域,K近邻算法(K-Nearest Neighbors, KNN)是一种非常直观且常用的分类算法。它是一种基于实例的学习方法,也被称为懒学习(Lazy Learning),因为它在训练阶段不进行任何模型的构建,所有的计算都推迟到测试阶段进行。KNN分类的核心思想是:给定一个测试样本,找到在训练集中与其距离最近的K个样本,然后根据这K个样本的标签进行预测。

本文将介绍KNN算法的基本原理、如何实现KNN分类,以及在实际使用中需要注意的几点。

一.KNN算法的基本原理

KNN算法的基本流程如下:

(1)选择距离度量:通常我们使用欧氏距离来衡量两个样本点之间的距离,但也可以选择其他距离度量,如曼哈顿距离、余弦相似度等。

(2)选择K值:选择K的大小会直接影响分类效果。K值太小容易受到噪声数据的影响,而K值过大可能导致分类结果过于平滑。

(3)找到K个邻居:对于测试样本,根据距离度量选择与之最接近的K个样本。

(4)投票决策:通过这K个邻居的类别标签进行投票,测试样本的预测标签通常由出现频率最高的类别决定。

二.KNN分类的实现

在Python中,我们可以通过 sklearn 库来快速实现KNN分类器。下面是一个使用KNN进行分类的基本示例:

导入必要的库

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score

 加载数据集
我们使用sklearn自带的鸢尾花(Iris)数据集,该数据集包含150个样本,4个特征,3个类别。

# 加载鸢尾花数据集
iris = load_iris()
X = iris.data  # 特征
y = iris.target  # 标签

数据集拆分
将数据集拆分为训练集和测试集,训练集占80%,测试集占20%。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

初始化KNN分类器并训练
我们创建一个KNN分类器实例,选择K=3。

# 初始化KNN分类器,设置K=3
knn = KNeighborsClassifier(n_neighbors=3)

# 在训练集上训练模型
knn.fit(X_train, y_train)

测试与评估
我们可以使用测试集来评估模型的准确性。

# 在测试集上做预测
y_pred = knn.predict(X_test)

# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy * 100:.2f}%")

KNN分类的优缺点
优点
简单易懂:KNN算法简单直观,不需要复杂的训练过程。
无参数假设:KNN不需要像其他算法那样对数据做参数假设,适应性强。
适合多分类问题:KNN能够有效地处理多类问题。
缺点
计算开销大:在测试阶段需要计算每个测试点与所有训练数据的距离,计算量大,尤其在数据量较大时,效率较低。
对噪声敏感:由于KNN依赖于距离度量,数据中的噪声点可能会影响分类结果。
需要存储整个训练集:KNN算法是懒学习,需要将训练集存储在内存中,可能会对内存消耗产生较大影响。
K值的选择与调优
选择合适的K值是KNN分类器表现的关键。过小的K值(例如1)容易过拟合,受噪声影响较大,而过大的K值会导致欠拟合。常用的选择方法是通过交叉验证来选择K值。 

from sklearn.model_selection import cross_val_score

# 使用交叉验证选择K值
k_values = range(1, 21)
cv_scores = [np.mean(cross_val_score(KNeighborsClassifier(n_neighbors=k), X, y, cv=5)) for k in k_values]

# 输出不同K值的交叉验证得分
for k, score in zip(k_values, cv_scores):
    print(f"K={k}, Cross-validation accuracy={score:.2f}")

 

 

import numpy as np
import math
from collections import Counter
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix, classification_report
import matplotlib.pyplot as plt

# 计算欧几里得距离
def euclidean_distance(x1, x2):
    """
    计算欧几里得距离
    x1, x2: 两个输入样本,numpy数组或列表
    """
    return math.sqrt(np.sum((x1 - x2) ** 2))

# 计算曼哈顿距离
def manhattan_distance(x1, x2):
    """
    计算曼哈顿距离(L1距离)
    x1, x2: 两个输入样本,numpy数组或列表
    """
    return np.sum(np.abs(x1 - x2))

# 计算闵可夫斯基距离
def minkowski_distance(x1, x2, p=3):
    """
    计算闵可夫斯基距离,p为距离的阶数
    x1, x2: 两个输入样本,numpy数组或列表
    p: 阶数,通常为 1 (曼哈顿距离) 或 2 (欧几里得距离)
    """
    return np.power(np.sum(np.abs(x1 - x2) ** p), 1/p)

# KNN 分类器类
class KNN:
    def __init__(self, k=3, distance_metric='euclidean'):
        """
        初始化 KNN 分类器
        
        k: 最近邻的个数
        distance_metric: 距离度量方式,'euclidean' 为欧几里得距离,'manhattan' 为曼哈顿距离,'minkowski' 为闵可夫斯基距离
        """
        self.k = k
        self.distance_metric = distance_metric

    def fit(self, X_train, y_train):
        """
        训练模型,保存训练数据
        
        X_train: 训练特征数据
        y_train: 训练标签数据
        """
        self.X_train = X_train
        self.y_train = y_train

    def predict(self, X_test):
        """
        对测试数据进行预测
        
        X_test: 测试特征数据
        返回预测标签
        """
        predictions = [self._predict(x) for x in X_test]
        return np.array(predictions)

    def _predict(self, x):
        """
        对单个样本进行预测
        
        x: 输入样本
        返回预测标签
        """
        # 根据指定的距离度量方法计算距离
        if self.distance_metric == 'euclidean':
            distances = [euclidean_distance(x, x_train) for x_train in self.X_train]
        elif self.distance_metric == 'manhattan':
            distances = [manhattan_distance(x, x_train) for x_train in self.X_train]
        elif self.distance_metric == 'minkowski':
            distances = [minkowski_distance(x, x_train) for x_train in self.X_train]
        else:
            raise ValueError(f"Unsupported distance metric: {self.distance_metric}")

        # 找到最近的 k 个邻居
        k_indices = np.argsort(distances)[:self.k]
        k_nearest_labels = [self.y_train[i] for i in k_indices]
        
        # 返回最常见的标签
        most_common = Counter(k_nearest_labels).most_common(1)
        return most_common[0][0]

# 加载 Iris 数据集
iris = load_iris()
X = iris.data  # 特征数据
y = iris.target  # 标签数据

# 切分数据集为训练集和测试集,70% 训练集,30% 测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 标准化数据,以确保不同特征的数值范围一致
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# 初始化 KNN 分类器
knn = KNN(k=5, distance_metric='minkowski')  # 使用闵可夫斯基距离
knn.fit(X_train, y_train)

# 预测
predictions = knn.predict(X_test)

# 计算准确率
accuracy = accuracy_score(y_test, predictions)
print(f"预测准确率: {accuracy * 100:.2f}%")

# 输出混淆矩阵和分类报告
print("\n混淆矩阵:")
print(confusion_matrix(y_test, predictions))

print("\n分类报告:")
print(classification_report(y_test, predictions))

# 绘制预测结果与真实结果对比的图表
def plot_confusion_matrix(cm, classes, title='Confusion Matrix', cmap=plt.cm.Blues):
    """
    绘制混淆矩阵
    cm: 混淆矩阵
    classes: 类别名
    """
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)

    # 绘制网格
    thresh = cm.max() / 2.
    for i, j in np.ndindex(cm.shape):
        plt.text(j, i, format(cm[i, j], 'd'),
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

# 计算混淆矩阵
cm = confusion_matrix(y_test, predictions)

# 绘制混淆矩阵
plt.figure(figsize=(8, 6))
plot_confusion_matrix(cm, classes=iris.target_names)
plt.show()

# 展示一些预测结果
for i in range(5):
    print(f"实际标签: {iris.target_names[y_test[i]]}, 预测标签: {iris.target_names[predictions[i]]}")

 

代码功能解释:
计算不同距离:

euclidean_distance:计算欧几里得距离。
manhattan_distance:计算曼哈顿距离。
minkowski_distance:计算闵可夫斯基距离,p 代表阶数,通常取 1(曼哈顿距离)或者 2(欧几里得距离)。
KNN 分类器:

在 KNN 类中,你可以选择不同的距离度量方式 ('euclidean', 'manhattan', 'minkowski'),通过 k 来设定邻居个数。
fit 方法保存训练数据,predict 方法对每个测试数据点进行预测。
_predict 方法对单个测试样本进行预测,通过计算与训练集中所有样本的距离来选择最近的 k 个邻居。
数据预处理:

使用 StandardScaler 来标准化数据,使得每个特征具有零均值和单位方差。
模型评估:

使用 accuracy_score 计算预测准确率。
使用 confusion_matrix 和 classification_report 来展示混淆矩阵和分类性能报告(包括精确度、召回率、F1 分数等)。
通过 matplotlib 绘制混淆矩阵,帮助可视化模型的分类效果。
数据集:

使用 sklearn.datasets 中的 Iris 数据集。该数据集包含 150 个样本,分别属于 3 个不同的鸢尾花种类,每个样本有 4 个特征。
输出:
准确率:模型对测试集的预测准确性。
混淆矩阵:展示真实标签与预测标签的对比。
分类报告:包含精确度、召回率、F1 分数等详细指标。
混淆矩阵图表:图形化展示分类性能。
这个实现包含了更多的功能,并且通过使用不同的距离度量方法,你可以探索 KNN 在不同设置下的表现。

三.总结

K 最近邻(KNN)算法是一种简单直观的监督学习算法,广泛应用于分类和回归问题。其核心思想是,通过计算待预测样本与训练集中的每个样本之间的距离,选择距离最近的 k 个样本(即“邻居”),然后根据这些邻居的标签或数值来进行预测。在分类问题中,KNN 通过多数投票原则决定最终分类结果;在回归问题中,则通常是取邻居标签的平均值。KNN 算法的优势在于不需要显式的训练过程,其预测过程依赖于对整个训练数据集的存储和计算,因此适合动态更新数据的场景。然而,KNN 算法的计算复杂度较高,尤其在数据集较大时,预测过程可能变得非常缓慢。为了提高效率,通常需要对数据进行预处理,如归一化或标准化,以消除不同特征尺度差异的影响。此外,K 值的选择以及距离度量方法(如欧几里得距离、曼哈顿距离等)会显著影响模型的表现,K 值过小可能导致过拟合,过大则可能导致欠拟合。KNN 的一个主要缺点是它对高维数据(即特征空间维度较大)不太敏感,因为高维空间的距离度量往往会失去区分度,导致“维度灾难”。总的来说,KNN 是一个易于理解和实现的算法,适用于样本量不大且特征维度较低的问题,但在大数据集和高维数据上可能不够高效。

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

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

相关文章

让Git走代理

有时候idea提交代码或者从github拉取代码,一直报错超时或者:Recv failure: Connection was reset,下面记录一下怎么让git走代理从而访问到github。 1.打开梯子 2.打开网络和Internet设置 3.设置代理 记住这个地址和端口 4.打开git bash终端 输入以下内容 git c…

CSS:导航栏三角箭头

用CSS实现导航流程图的样式。可根据自己的需求进行修改,代码精略的写了一下。 注:场景一和场景二在分辨率比较低的情况下会有一个1px的缝隙不太优雅,自行处理。有个方法是直接在每个外面包一个DIV,用动态样式设置底色。 场景一、…

第4章-计划 4.3 订计划、勤跟踪、要闭环

4.3 订计划、勤跟踪、要闭环 1.制订好的第一版计划先要基线化,确保有据可依2.计划要监督执行,发现延期时要“喊出来”3.计划要赶得上变化4.资源保障是计划能够执行的依赖 坚定执行制订好的计划,监督执行效果,计划产生偏差时及时制…

在 WPF 中,如何实现数据的双向绑定?

在 WPF 中,数据绑定是一个非常重要的特性,它允许 UI 与数据源之间自动同步。双向绑定是一种常见的绑定方式,当数据源更新时,UI 会自动更新;同样,当 UI 中的元素(如文本框)发生改变时…

Java面向对象编程进阶之包装类

Java面向对象编程进阶之包装类 一、为什么要使用包装类二、掌握基本数据类型与包装类之间的转换1、为什么需要转换?2、如何转换? 三、String与基本数据类型、包装类之间的转换1、案例2、特别注意 一、为什么要使用包装类 为了使得基本类型的数据变量具备…

基于Spring Boot与Redis的令牌主动失效机制实现

目录 前言1. 项目结构和依赖配置1.1 项目依赖配置1.2 Redis连接配置 2. 令牌主动失效机制的实现流程2.1 登录成功后将令牌存储到Redis中2.2 使用拦截器验证令牌2.3 用户修改密码后删除旧令牌 3. Redis的配置与测试4. 可能的扩展与优化结语 前言 在现代Web系统中,用…

yolov8-cls的onnx与tensorrt推理

本文不生产技术,只做技术的搬运工! 前言 最近需要使用yolov8-cls进行模型分类任务,但是使用ultralytics框架去部署非常不方便,因此打算进行onnx或者tensorrt去部署,查看了很多网上的帖子,并没有发现有完整复现yolov8-cls前处理(不需要后处理)的"轮子",通过自己debug…

Acrobat Pro DC 2023(pdf免费转化word)

所在位置 通过网盘分享的文件:Acrobat Pro DC 2023(64bit).tar 链接: https://pan.baidu.com/s/1_m8TT1rHTtp5YnU8F0QGXQ 提取码: 1234 --来自百度网盘超级会员v4的分享 安装流程 打开安装所在位置 进入安装程序 找到安装程序 进入后点击自定义安装,这里…

VMware和CentOS 7.6 Linux操作系统的安装使用

1. 安装VMware 安装VMware之前,有些电脑是需要去BIOS里修改设置开启cpu虚拟化设备支持才能安装。如果运气不好在安装过程中安装不了的话就自行百度吧。 打开 VMware 的官网: https://www.vmware.com/ 点击 product,往下滑找到 see desktop hypeerviso…

手把手教你:如何从零开始实施一套OA办公系统!

很多朋友都吐槽说公司的各种各样的信息啊文件啊越积越多,导致管理起来越来越麻烦。早就跟大家说过,尤其是在提高工作效率、优化资源配置和促进信息共享方面,OA(办公自动化)系统发挥着不可替代的作用,早安排…

网页web无插件播放器EasyPlayer.js播放器返回错误 Incorrect response MIME type 的解决方式

在使用EasyPlayer.js播放器进行视频流播放时,尤其是在SpringBoot环境中部署静态资源时,可能会遇到“Incorrect response MIME type”的错误,这通常与WebAssembly(WASM)文件的MIME类型配置有关。 WASM是一种新的代码格式…

element-plus <el-date-picker>日期选择器踩坑!!!!

我怎么一上午踩两个坑&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff08;大声bb&#xff09; 原来的vue2老项目是这样写的 <el-form-item label"时间" prop"time"><el-date-pickerv-model"addForm.time"typ…

# 如何查看 Ubuntu 版本?

如何查看 Ubuntu 版本&#xff1f; 要查看‌Ubuntu版本&#xff0c;你可以通过以下几种方法&#xff1a; 1. 使用‌lsb_release 命令‌查看 使用 lsb_release -a 命令可以查看Ubuntu的详细版本信息&#xff0c;包括发行版ID、版本号以及版本代号。‌ ‌### 2、查看 /etc/is…

常用的生物医药专利查询数据库及网站(很全!)

生物医药专利信息检索是药物研发前期不可或缺的一步&#xff0c;通过对国内外生物医药专利网站信息查询&#xff0c;可详细了解其专利技术&#xff0c;进而有效降低药物研发过程中的风险。 目前主要使用的生物医药专利查询网站分为两大类&#xff0c;一个是免费生物医药专利查询…

第四节-OSI-网络层

数据链路层&#xff1a;二层--MAC地址精确定位 Ethernet 2&#xff1a; 报头长度&#xff1a;18B 携带的参数&#xff1a;D MAC /S MAC/TYPE(标识上层协议)/FCS 802.3 报头长度&#xff1a;26B 携带的参数&#xff1a;D MAC/S MAC/LLC(标识上层协议)/SNAP&#xff08;标识…

Python数据分析NumPy和pandas(二十七、数据可视化 matplotlib API 入门)

数据可视化或者数据绘图是数据分析中最重要的任务之一&#xff0c;是数据探索过程的一部分&#xff0c;数据可视化可以帮助我们识别异常值、识别出需要的数据转换以及为模型生成提供思考依据。对于Web开发人员&#xff0c;构建基于Web的数据可视化显示也是一种重要的方式。Pyth…

【前端】深入浅出 - TypeScript 的详细讲解

TypeScript 是一种静态类型编程语言&#xff0c;它是 JavaScript 的超集&#xff0c;添加了类型系统和编译时检查。TypeScript 的主要目标是提高大型项目的开发效率和可维护性。本文将详细介绍 TypeScript 的核心概念、语法、类型系统、高级特性以及最佳实践。 1. TypeScript…

查询DBA_FREE_SPACE缓慢问题

这个是一个常见的问题&#xff0c;理论上应该也算是一个bug&#xff0c;在oracle10g&#xff0c;到19c&#xff0c;我都曾经遇到过&#xff1b;今天在给两套新建的19C RAC添加监控脚本时&#xff0c;又发现了这个问题&#xff0c;在这里记录一下。 Symptoms 环境&#xff1a;…

The Internals of PostgreSQL 翻译版 持续更新...

为了方便自己快速学习&#xff0c;整理了翻译版本&#xff0c;目前翻译的还不完善&#xff0c;后续会边学习边完善。 文档用于自己快速参考&#xff0c;会持续修正&#xff0c;能力有限,无法确保正确!!! 《The Internals of PostgreSQL 》 不是 《 PostgreSQL14 Internals 》…

机器学习 ---模型评估、选择与验证(1)

目录 前言 一、为什么要有训练集与测试集 1、为什么要有训练集与测试集 2、如何划分训练集与测试集 二、欠拟合与过拟合 1、什么是欠拟合与欠拟合的原因 2、什么是过拟合与过拟合的原因 一些解决模型过拟合和欠拟合问题的常见方法&#xff1a; 解决过拟合问题&#…