ML 系列:机器学习和深度学习的深层次总结( 15) — KNN — 第 1 部分

一、说明

        K-最近邻 (KNN) 算法是一种流行的监督机器学习算法,用于分类和回归任务。它是非参数惰性学习算法的一个典型例子。KNN 被认为是一种惰性学习算法,因为它在训练阶段不对底层数据分布做出任何假设,也不从训练数据中学习特定模型。相反,它是一种“惰性”或“延迟”学习,它只是记住训练数据集。

二、KNN算法

        KNN 也是一种非参数算法,因为它没有在训练过程中确定的固定数量的参数。KNN 中的参数数量会随着训练数据的大小而增长,因为每个数据点都会成为一个参数。这与线性回归或神经网络等参数模型不同,这些模型无论训练数据大小如何,都有固定数量的参数。

        在 KNN 中,根据 k 个最接近匹配的训练样本中的多数标签,将一个标签(表示为 x_i)分配给一个实例。这种方法允许 KNN 通过比较实例与其相邻数据点之间的相似性来进行预测。
在 K 最近邻 (KNN) 算法中,通过使用距离度量搜索其最近邻居来定位数据点。然后,该算法根据多数类或其 k 个最近邻居的平均值对输出进行分类或预测。例如,在 k=5 的分类问题中,当向算法呈现新的数据点时,将考虑训练集中距离新点最近的五个数据点(由欧几里得距离等距离度量确定)。新点的类标签是根据其五个邻居中的多数类分配的。在回归问题中,算法不是分配类标签,而是通过取其 k 个最近邻居的平均值来预测输出值。图 9-4 说明了 KNN 算法的工作原理。

图 1.“KNN”算法的工作原理

        新数据点用问号表示其未知的标签或值。如前所述,该算法利用 k 个最接近的训练样本中的多数标签对新数据点的输出进行分类或预测。

        在 KNN 中,超参数 k 的选择至关重要,因为它决定了用于预测的邻居数量。k 值越小,决策边界就越复杂,这可能会增加过度拟合训练数据的风险。另一方面,k 值越大,决策边界就越平滑,但可能会导致欠拟合,即模型过度简化数据点之间的关系。

        确定 k 的最佳值通常取决于手头的具体问题,可以通过实验或交叉验证来完成。选择合适的 k 值以在未知数据上实现令人满意的性能,在模型复杂性和泛化之间取得平衡至关重要。

图2显示了选择k值的效果。

图 2. 不同 k 值的选择

图2中,横轴表示特征个数或者说数字k,横轴也表示模型的准确率。

        在本教程中,我们将从头开始探索在 Python 中实现 K-最近邻 (KNN) 算法。KNN 是一种用于分类和回归任务的基本机器学习算法。通过从头开始构建 KNN,我们将更深入地了解其内部工作原理,并学习如何将其应用于现实世界的数据集。

让我们深入研究如何逐步实现 KNN 算法!

三、KNN算法的Python实现

3.1 步骤 1:导入库

        我们首先导入必要的库。我们将使用 NumPy 进行数值计算、使用 Matplotlib 进行数据可视化、使用 mlxtend 绘制决策区域,并使用 scikit-learn 生成合成数据并将其拆分为训练集和测试集。

import numpy as np
import matplotlib.pyplot as plt
from mlxtend.plotting import plot_decision_regions
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split

3.2 第 2 步:定义 KNN 类

        该类KNN是我们 K-最近邻 (KNN) 算法实现的核心组件。在这个类中,我们封装了实例化、训练和利用 KNN 模型进行预测所需的所有基本功能。该类中的关键方法包括:

  • __init__:使用默认值初始化 KNN 分类器k,表示预测期间要考虑的邻居数量。
  • fit:将模型与提供的训练数据进行拟合,存储训练特征(X_train)和相应的标签(y_train)。
  • euclidean_distance:计算两个数据点之间的欧几里得距离,这是确定实例之间相似性的关键指标。
  • predict:获取一组输入数据点并返回基于 k 个最近邻的预测标签数组。
  • _predictpredict:通过识别 k 个最近邻并应用多数投票方案来计算单个数据点的预测所使用的内部方法。

        通过将这些功能封装在KNN类中,我们创建了 KNN 算法的模块化和可重用实现,使其更易于理解、维护和扩展。这是 KNN 类:

class KNNClassification:def __init__(self, k=3):self.k = kdef fit(self, X, y):self.X_train = Xself.y_train = ydef euclidean_distance(self, x1, x2):return np.sqrt(np.sum((x1 - x2)**2))def predict(self, X):y_pred = [self._predict(x) for x in X]return np.array(y_pred)def _predict(self, x):distances = [self.euclidean_distance(x, x_train) for x_train in self.X_train]k_indices = np.argsort(distances)[:self.k]k_nearest_labels = [self.y_train[i] for i in k_indices]most_common = max(set(k_nearest_labels), key=k_nearest_labels.count)return most_commondef plot_data(X, y):# (o==circle, for train) and (s==square for test)plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train, s=100, cmap='jet', marker='o')plt.scatter(x_test[:, 0], x_test[:, 1], c=y_test, s=100, cmap='jet', marker='s')plt.xlabel('Feature 1')plt.ylabel('Feature 2')plt.title('Generated Data')plt.show()

        这部分代码是主要执行部分,我们在其中实例化 KNN 算法,在合成数据上对其进行训练,可视化决策边界,评估其性能,并绘制训练和测试数据点以及预测标签。

class KNN:def __init__(self, k=3):self.k = kdef fit(self, X, y):self.X_train = Xself.y_train = ydef euclidean_distance(self, x1, x2):return np.sqrt(np.sum((x1 - x2)**2))def predict(self, X):y_pred = [self._predict(x) for x in X]return np.array(y_pred)def _predict(self, x):distances = [self.euclidean_distance(x, x_train) for x_train in self.X_train]k_indices = np.argsort(distances)[:self.k]k_nearest_labels = [self.y_train[i] for i in k_indices]most_common = max(set(k_nearest_labels), key=k_nearest_labels.count)return most_commondef plot_data(X, y):plt.scatter(X[:, 0], X[:, 1], c=y, s=100, cmap='jet', marker='o')plt.xlabel('Feature 1')plt.ylabel('Feature 2')plt.title('Generated Data')plt.show()if __name__ == "__main__":# Generate synthetic data using scikit-learn's make_classification functionX, y = make_classification(n_samples=20, n_features=2, n_informative=2, n_redundant=0,n_clusters_per_class=1, class_sep=1., random_state=23)plot_data(X, y)# Split data into training and testing setsx_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=19)knn = KNN(k=3)knn.fit(x_train, y_train)plot_decision_regions(X, y, clf=knn, legend=2)plt.xlabel('Feature 1')plt.ylabel('Feature 2')plt.title('KNN Decision Boundary')plt.show()# Predict classes for the test datay_pred = knn.predict(x_test)# Calculate accuracyaccuracy = np.mean(y_pred == y_test) * 100print(f"Accuracy: {accuracy:.2f}%")# Plot the training and test data (o==circle, for train) and (s==square for test)plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train, s=100, cmap='jet', marker='o', label='Train (Circle)')plt.scatter(x_test[:, 0], x_test[:, 1], c=y_test, s=100, cmap='jet', marker='s', label='Test (Square)')plt.scatter(x_test[:, 0], x_test[:, 1], c=y_pred, s=150, cmap='jet', marker='x', label='Predicted Test (Cross)')plt.xlabel('Feature 1')plt.ylabel('Feature 2')plt.title(f'Train-Test, Predicted, accuracy = {accuracy}')plt.legend()plt.show()

四、K 最近邻的挑战

        虽然 K-最近邻 (KNN) 是一种简单有效的算法,但它也面临挑战。在本次讨论中,我们将探讨使用 KNN 时遇到的一些常见问题,并通过代码示例进行演示。通过研究 KNN 如何处理不断增加的数据集大小,我们旨在说明该算法的可扩展性限制,并阐明计算时间和内存使用之间的权衡。让我们深入研究代码以揭示这些挑战。

import time# Define a range of sample sizes to test
sample_sizes = [1000, 5000, 10000, 50000, 100000]# Lists to store time and memory usage for each sample size
execution_times = []
memory_usages = []# Loop through each sample size
for sample_size in sample_sizes:print(f"Testing with {sample_size} data points...")# Generate synthetic dataX, y = make_classification(n_samples=sample_size, n_features=2, n_informative=2, n_redundant=0,n_clusters_per_class=1, class_sep=1., random_state=42)# Split data into training and testing setsx_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=42)# Calculate memory usage for training datatrain_memory_usage = x_train.size * x_train.itemsizememory_usages.append(train_memory_usage)# Instantiate and fit the KNN modelmodel = KNN(3)model.fit(x_train, y_train)# Measure prediction time for a single test data pointstart_time = time.time()model.predict(x_test[[0], :])end_time = time.time()execution_time = end_time - start_timeexecution_times.append(execution_time)# Plotting the results
plt.figure(figsize=(10, 5))# Plot execution time
plt.subplot(1, 2, 1)
plt.plot(sample_sizes, execution_times, marker='o')
plt.xlabel('Number of Data Points')
plt.ylabel('Execution Time (seconds)')
plt.title('Execution Time vs. Number of Data Points')# Plot memory usage
plt.subplot(1, 2, 2)
plt.plot(sample_sizes, memory_usages, marker='o')
plt.xlabel('Number of Data Points')
plt.ylabel('Memory Usage (bytes)')
plt.title('Memory Usage vs. Number of Data Points')plt.tight_layout()
plt.show()

运行上述代码后,我们可以看到如下图所示的情节:

图 1. KNN 的计算时间和内存使用情况

五、KNN 回归:使用 K 最近邻进行预测建模

        KNN 回归涉及通过确定每个数据点的最近邻居目标值的平均值来预测连续目标值。我想改变以前的代码并将其转换为适合回归的代码。

回归和分类代码之间的差异:

  1. 数据集生成:
  • 上一个(分类):使用“make_classification”生成数据集以创建合成分类数据。
  • 当前(回归):使用“make_regression”生成合成回归数据。

2.模型预测:

  • KNN 模型预测每个数据点的离散类标签而不是连续的目标值。

3.评估指标:

  • 由于这是一项回归任务,因此可以使用传统评估指标(例如均方误差(MSE)或 R 平方)来代替准确度。

4.可视化:

  • 之前:使用“plot_decision_regions”可视化决策边界以说明分类区域。
  • 当前:回归线可视化,以展示 KNN 模型对回归任务的预测能力。

5.标签编码:

  • 回归不需要标签编码,因为目标值是连续的而不是整数。

以下是使用 KNN 进行回归的修改后的代码:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_splitclass KNNRegression:def __init__(self, k=3):self.k = kdef fit(self, X, y):self.X_train = Xself.y_train = ydef euclidean_distance(self, x1, x2):return np.sqrt(np.sum((x1 - x2)**2))def predict(self, X):y_pred = [self._predict(x) for x in X]return np.array(y_pred)def _predict(self, x):distances = [self.euclidean_distance(x, x_train) for x_train in self.X_train]k_indices = np.argsort(distances)[:self.k]k_nearest_labels = [self.y_train[i] for i in k_indices]return np.mean(k_nearest_labels)if __name__ == "__main__":# Generate synthetic regression dataX, y = make_regression(n_samples=100, n_features=1, noise=10, random_state=42)# Instantiate and fit the KNN regression modelknn = KNNRegression(k=3)knn.fit(X, y)# Generate a range of feature values for plotting the regression linex_range = np.linspace(min(X), max(X), num=100).reshape(-1, 1)# Predict target values for the feature rangey_pred = knn.predict(x_range)# Plot the data points and the regression lineplt.scatter(X, y, color='blue', s=30, marker='o', label='Data')plt.plot(x_range, y_pred, color='red', linewidth=2, label='KNN Regression')plt.xlabel('Feature')plt.ylabel('Target')plt.title('KNN Regression')plt.legend()plt.show()

通过平滑的回归线描绘特征和目标变量之间的关系:

图 2. KNN 回归线

六、探索 K 最近邻 (KNN) 算法中 K 的影响:平衡过度拟合和欠拟合

        在本分析中,我们深入探讨了 K 最近邻 (KNN) 算法中参数“K”的意义及其对分类准确性、决策边界、过度拟合和欠拟合的影响。

        在 K 最近邻 (KNN) 算法中,如果 K 值太小,通常就会发生过拟合。如果 K 值较小,模型就会对数据中的噪声和异常值过于敏感,从而导致决策边界过于复杂,与训练数据拟合得过于紧密。这可能会导致模型对未知数据的泛化能力较差,因为模型可能会捕捉噪声而不是底层模式。

        相反,当K 值过大时,可能会出现欠拟合。如果 K 值过大,模型会对过多的邻居进行平均,导致决策边界过于简单,无法捕捉数据的真实结构。这会导致训练和测试数据集的准确率都很低,表明模型无法充分捕捉底层模式的复杂性。

        通过系统地改变 K 的值并观察其对模型性能和行为的影响,我们可以深入了解所涉及的权衡,并发现基于 KNN 任务中参数选择的最佳策略,确保过度拟合和欠拟合之间的平衡。

from sklearn.metrics import mean_squared_errordef test_k_values(X_train, y_train, X_range, k_values):fig, axs = plt.subplots(2, 2, figsize=(12, 10))axs = axs.flatten()for i, k in enumerate(k_values):# The regression class that we wrote in the previous codesknn_reg = KNNRegression(k=k)# Fit the KNN regression model to the training dataknn_reg.fit(X_train, y_train)# Predict target values for the range of feature valuesy_pred = knn_reg.predict(X_range)mse = mean_squared_error(y_train, knn_reg.predict(X_train))axs[i].scatter(X_train, y_train, color='blue', s=30, marker='o', label='Data')axs[i].plot(X_range, y_pred, color='red', linewidth=2, label=f'KNN Regression (K={k}), MSE: {mse:.2f}')axs[i].set_xlabel('Feature')axs[i].set_ylabel('Target')axs[i].set_title(f'KNN Regression (K={k})')axs[i].legend()plt.tight_layout()plt.show()if __name__ == "__main__":# Generate synthetic regression dataX, y = make_regression(n_samples=100, n_features=1, noise=10, random_state=42)X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=42)# Generate a range of feature values for plotting the regression lineX_range = np.linspace(min(X), max(X), num=100).reshape(-1, 1)# Test different values of K and plot the resultsk_values = [1, 3, 5, 7]test_k_values(X_train, y_train, X_range, k_values)

这是代码的输出:

图 3. 在网格中绘制结果

概述 K 最近邻 (KNN) 的优缺点:

图 4. KNN 的优缺点

七、K 最近邻 (KNN) 算法的增强和扩展:解决限制并提高性能

        K 最近邻 (KNN) 算法虽然简单直观,但也有其缺点。然而,研究人员和从业者已经开发出各种改进和扩展来解决这些限制。这些方法中的每一种都旨在解决算法缺点的特定方面。例如,加权 KNN 或距离加权 KNN等技术试图通过根据距离为相邻点分配不同的权重来减轻算法对不相关特征的敏感性。同样,KD 树Ball 树等方法通过将数据组织成空间数据结构来优化算法对大型数据集的计算效率。在我们机器学习系列的下一篇中,我们将深入研究这些改进和扩展,探索它们如何增强 KNN 算法的性能和多功能性。

八、结论 

        在第 15 天,我们讨论了 KNN 的概念以及从头开始的分类和回归实现。在即将发布的文章《ML 系列:第 16 天 — 提高 KNN 效率:使用 KD 树和 Ball 树实现更快的算法》中,我将探讨 KNN、KD 树和 Ball 树的一些改进。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Golang | Leetcode Golang题解之第466题统计重复个数

题目&#xff1a; 题解&#xff1a; func getMaxRepetitions(s1 string, n1 int, s2 string, n2 int) int {n : len(s2)cnt : make([]int, n)for i : 0; i < n; i {// 如果重新给一个s1 并且s2是从第i位开始匹配 那么s2可以走多少位&#xff08;走完了就从头开始走p1, p2 :…

开发环境搭建之JAVA多个JDK版本安装

由于项目需要安装多个版本JDK、所以在此记录一下安装过程&#xff1a; 下载JDK1.8 11 17 等多个版本 简单粗暴一看就会、直接从官网下载exe安装包、然后配置环境变量即可 JDK1.8 JDK11 JDK17 安装完成之后如下图&#xff1a; 环境变量配置 右击“我的电脑”属性、找到…

Kron Reduction消去法如何操作,矩阵推导过程

三阶矩阵消去单节点 在电力系统中,母线上的电流注入始终为0,这样的节点可以通过一定的方法消除。以三节点为例,假设注入节点3的电流为0,则: [ I 1 I 2 I 3 ] = [ I 1 I 2 0 ] = [ Y 11 Y 12 Y 13 Y 21 Y 22 Y 23 Y 31 Y 32 Y 33 ] [ V 1 V 2 V 3 ] \left[\begin{array}{…

计算机网络:数据链路层 —— 数据链路层概述

文章目录 数据链路层主要功能 基本概念链路数据链路帧 数据链路层 在计算机网络中&#xff0c;链路层&#xff08;Data Link Layer&#xff09;是网络协议栈中的一层&#xff0c;负责管理和控制链路的建立、维护和释放&#xff0c;以及处理链路层的数据帧传输和错误控制等功能…

go发送邮件:在Go语言中实现发邮件的教程?

go发送邮件的教程指南&#xff1f;怎么使用Go语言发送电子邮件&#xff1f; Go语言&#xff0c;作为一种简洁、高效且并发性强的编程语言&#xff0c;自然也提供了丰富的库来支持邮件发送功能。AokSend将详细介绍如何在Go语言中实现发送邮件的功能&#xff0c;帮助你快速掌握这…

服务器数据恢复—硬盘坏扇区导致Linux系统服务器数据丢失的数据恢复案例

服务器数据恢复环境&#xff1a; 一台linux操作系统网站服务器&#xff0c;该服务器上部署了几十个网站&#xff0c;使用一块SATA硬盘。 服务器故障&原因&#xff1a; 服务器在工作过程中突然宕机。管理员尝试重新启动服务器失败&#xff0c;于是将服务器上的硬盘拆下检测…

腾讯云SDK地址生成器

音视频终端 SDK&#xff08;腾讯云视立方&#xff09;将新版连麦管理方案的多个功能集成至 腾讯云视立方控制台 > 连麦管理&#xff0c;便于用户快捷使用&#xff0c;具体分为快速上手、连麦应用、用量统计和地址生成器四个功能页面。更多连麦功能说明&#xff0c;请参见 新…

查询v$asm_disk等待enq: DD - contention

1.两个节点查询v$asm_disk均卡住&#xff0c;等待enq: DD - contention&#xff0c;阻塞源头为rbal进程&#xff0c;rbal进程未发生阻塞&#xff0c;未在异常等待事件上。 2.阻塞源头RBAL&#xff0c;在CPU上运行。没有在做rebalance磁盘平衡。 3.diag诊断日志中&#xff0c;阻…

springboot 整合 rabbitMQ(2)

springboot 整合 rabbitMQ&#xff08;1&#xff09;-CSDN博客 上期说了rabbitMQ的基础用法&#xff08;普通队列模式&#xff09; 这期学习一下如何防止消息重复消费和进阶用法&#xff08;订阅者模式&#xff09; 目录 重复消费问题 导致 RabbitMQ 重复消费问题的原因&a…

《Windows PE》4.1.4 手工重构导入表

接下来我们做一个稍微复杂一些的实验&#xff0c;实验需要四个程序&#xff1a; HelloWorld.exe&#xff1a;弹出MessageBox窗口&#xff08;实验1已实现&#xff09;。 Regedit.exe&#xff1a;添加注册表启动项。 LockTray.exe&#xff1a;锁定任务栏窗口。 UnLockTray.exe&…

pandas的用法

1.简介&#xff1a; pandas是一个开源的python数据分析库提供了快速&#xff0c;灵活和表达力强的数据结构&#xff0c;使数据清洗和分析工作变得更加简单易行。pandas的核心数据结构是DataFrame和Series 2.DataFrame的基本操作&#xff1a; DataFrame是pandas库中的一个二维…

【项目记录】大模型基于llama.cpp在Qemu-riscv64向量扩展指令下的部署

概述 本文在qemu-riscv64平台上&#xff0c;利用向量扩展指令加速运行基于llama.cpp构建的大模型。 参考博客链接&#xff1a; Accelerating llama.cpp with RISC-V Vector Extension 基于RVV的llama.cpp在Banana Pi F3 RISCV开发板上的演示 llama.cpp工程 Llama.cpp是一个基…

AI教父荣获2024诺贝尔物理学奖:杰弗里·辛顿和他的深度学习之路!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

Chrome浏览器调用ActiveX控件--allWebOffice控件功能介绍

allWebOffice控件概述 allWebOffice控件能够实现在浏览器窗口中在线操作微软Office及WPS办公文档的应用&#xff08;阅读、编辑、保存等&#xff09;&#xff0c;支持编辑文档时保留修改痕迹&#xff0c;支持书签位置内容动态填充&#xff0c;支持公文套红&#xff0c;支持文档…

springMVC添加webapp

项目结构-->模块-->找到想添加的模块下的web 点击号 添加路径 会在.../src/main/目录下自动生成目录

Golang | Leetcode Golang题解之第467题环绕字符串中唯一的子字符串

题目&#xff1a; 题解&#xff1a; func findSubstringInWraproundString(p string) (ans int) {dp : [26]int{}k : 0for i, ch : range p {if i > 0 && (byte(ch)-p[i-1]26)%26 1 { // 字符之差为 1 或 -25k} else {k 1}dp[ch-a] max(dp[ch-a], k)}for _, v :…

【xilinx-versal】【Petalinux】I2C驱动开发问题记录

问题 调试中发现系统起来后无I2C设备。 仔细查找后发现没有配置versal的I2C控制器。 解决方法 打开versal的I2C控制器的配置 起来后I2C设备注册成功

使用idea和vecode创建vue项目并启动(超详细)

一、idea创建vue项目 创建项目之前先下载好插件 新建项目找到vue生成器 写好名称&#xff0c;找到自己需要存放的地址&#xff0c;node解释器安装方式可以看我上一个博客&#xff0c;vueCLI是选择vue的版本&#xff0c;我们可以使用idea自带的vue版本默认是vue3&#xff0c;创…

标准正态分布的数据 tensorflow 实现正态分布图,python 编程,数据分析和人工智能

import tensorflow as tf import matplotlib.pyplot as plt # 设置随机种子以获得可重复的结果 tf.random.set_seed(42) # 生成正态分布的数据 # mean0 和 stddev1 表示生成标准正态分布的数据 # shape(1000,) 表示生成1000个数据点 data tf.random.normal(mean0, stddev1, …

postman变量,断言,参数化

环境变量 1.创建环境变量 正式环境是错误的&#xff0c;方便验证环境变化 2.在请求中添加变量 3.运行前选择环境变量 全局变量 能够在任何接口访问的变量 console中打印日志 console.log(responseBody);//将数据解析为json格式 var data JSON.parse(responseBody); conso…