使用数学方法实现K-Nearest Neighbors(KNN)算法

news2025/1/9 16:25:49

目录

​编辑

引言

KNN算法的数学基础

1. 距离度量

欧氏距离

曼哈顿距离

2. 寻找最近邻

3. 决策规则

分类

回归

4. 权重

KNN算法的实现步骤

1. 参数选择

2. 实现

导入必要的库

加载数据集

划分训练集和测试集

创建KNN模型

训练模型

预测测试集

计算准确率

结论


引言

K-Nearest Neighbors(KNN)算法是一种简单而强大的机器学习算法,它基于一个直观的概念:相似的实例倾向于有相似的标签。这种基于实例的学习意味着KNN不需要从训练数据中学习一个判别函数或决策规则;相反,它仅仅是将训练数据存储起来,并且在预测时寻找训练集中与新数据点最相似的实例。本文将详细介绍KNN算法的数学基础和实现步骤,帮助读者理解并实现这一算法。

KNN算法的数学基础

1. 距离度量

KNN算法的核心在于计算实例之间的距离。以下是几种常用的距离度量方法:

欧氏距离

欧氏距离是最常用的距离度量之一,它源自欧几里得几何学。对于两个点 ( x = (x_1, x_2, ..., x_n) ) 和 ( y = (y_1, y_2, ..., y_n) ),欧氏距离定义为:
[
d(x, y) = \sqrt{\sum_{i=1}{n} (x_i - y_i)2}
]
这个公式计算了两点在n维空间中的直线距离。在实际应用中,欧氏距离因其直观性和计算简单而被广泛使用。它适用于许多不同类型的数据集,尤其是当所有特征都在同一尺度上并且对结果有相似影响时。

为了更好地理解欧氏距离的计算,我们可以添加一个简单的Python函数来计算两个点之间的欧氏距离:

import math

def euclidean_distance(x, y):
    return math.sqrt(sum((a - b) ** 2 for a, b in zip(x, y)))

# 示例使用
point1 = (1, 2, 3)
point2 = (4, 5, 6)
print("欧氏距离:", euclidean_distance(point1, point2))
曼哈顿距离

曼哈顿距离,也称为城市街区距离,是另一种常用的距离度量方法。对于两个点 ( x ) 和 ( y ),曼哈顿距离定义为:
[
d(x, y) = \sum_{i=1}^{n} |x_i - y_i|
]
这个公式计算了两点在n维空间中的“街区”距离,即沿着坐标轴移动的总距离。曼哈顿距离在某些情况下比欧氏距离更具有鲁棒性,尤其是在特征空间的各个维度是正交的情况下。这种距离度量对于那些特征之间相互独立且对结果影响不同的数据集特别有用。

同样,我们可以编写一个Python函数来计算两个点之间的曼哈顿距离:

def manhattan_distance(x, y):
    return sum(abs(a - b) for a, b in zip(x, y))

# 示例使用
point1 = (1, 2, 3)
point2 = (4, 5, 6)
print("曼哈顿距离:", manhattan_distance(point1, point2))

2. 寻找最近邻

在确定了距离度量方法后,下一步是寻找最近邻。对于一个新的实例,算法需要计算它与训练集中每个实例的距离,并找出距离最小的K个实例。这个过程可以通过遍历训练集中的所有实例来实现,然后根据计算出的距离进行排序,选择距离最小的K个实例。这一步骤是KNN算法中的关键,因为它直接影响到分类或回归的准确性。

为了实现这一步骤,我们可以编写一个函数来找到给定点的K个最近邻:

def find_k_nearest_neighbors(X_train, y_train, test_point, k):
    distances = [(manhattan_distance(test_point, train_point), label) for train_point, label in zip(X_train, y_train)]
    sorted_distances = sorted(distances, key=lambda x: x[0])
    neighbors = sorted_distances[:k]
    return neighbors

# 示例使用
X_train = [(1, 2), (3, 4), (5, 6), (7, 8)]
y_train = [0, 1, 0, 1]
test_point = (2, 3)
k = 2
k_nearest_neighbors = find_k_nearest_neighbors(X_train, y_train, test_point, k)
print("K个最近邻:", k_nearest_neighbors)

3. 决策规则

分类

在分类问题中,最常见的决策规则是多数投票法。即在K个最近邻中,出现次数最多的类别将被赋予新实例。这种方法简单直观,但在某些情况下可能需要更复杂的决策规则,例如加权投票,其中距离新实例更近的邻居具有更大的权重。加权投票可以提高分类的准确性,尤其是在数据集中的类别分布不均匀时。

为了实现多数投票法,我们可以编写一个函数来根据K个最近邻的标签进行预测:

def predict_classification(k_nearest_neighbors):
    labels = [neighbor[1] for neighbor in k_nearest_neighbors]
    most_common = max(set(labels), key=labels.count)
    return most_common

# 示例使用
k_nearest_neighbors = [(1, 0), (2, 1), (3, 0)]
predicted_label = predict_classification(k_nearest_neighbors)
print("预测的标签:", predicted_label)
回归

在回归问题中,可以通过取K个最近邻的目标值的平均值来预测新实例的目标值。这种方法称为KNN回归,它是一种非参数方法,不需要对数据的分布做出任何假设。KNN回归对于捕捉数据中的局部模式非常有效,尤其是在数据集具有复杂结构时。

为了实现KNN回归,我们可以编写一个函数来计算K个最近邻的目标值的平均值:

def predict_regression(k_nearest_neighbors):
    labels = [neighbor[1] for neighbor in k_nearest_neighbors]
    return sum(labels) / len(labels)

# 示例使用
k_nearest_neighbors = [(1, 10), (2, 20), (3, 15)]
predicted_value = predict_regression(k_nearest_neighbors)
print("预测的值:", predicted_value)

4. 权重

在某些情况下,可以给不同的邻居分配不同的权重,这通常基于它们与新实例的距离。权重通常与距离成反比,即距离越近的邻居对预测结果的影响越大。这种方法称为加权KNN,它可以提高模型的预测精度。权重的分配可以是线性的,也可以是非线性的,具体取决于问题的性质和数据的特点。

为了实现加权KNN,我们可以修改预测函数来考虑权重:

def predict_weighted(k_nearest_neighbors):
    total_weight = sum(1 / neighbor[0] for neighbor in k_nearest_neighbors)
    weighted_sum = sum((neighbor[1] / neighbor[0]) for neighbor in k_nearest_neighbors)
    return weighted_sum / total_weight

# 示例使用
k_nearest_neighbors = [(1, 10), (2, 20), (3, 15)]
predicted_value = predict_weighted(k_nearest_neighbors)
print("加权预测的值:", predicted_value)

KNN算法的实现步骤

1. 参数选择

KNN算法中的一个关键参数是K值的选择。K值的选择会影响模型的性能,通常需要通过交叉验证等方法来确定最优的K值。太小的K值可能会导致过拟合,而太大的K值可能会导致欠拟合。因此,选择合适的K值对于模型的性能至关重要。此外,距离度量的选择和权重的分配也是影响模型性能的重要因素。

为了选择最优的K值,我们可以使用交叉验证:

from sklearn.model_selection import cross_val_score

def select_optimal_k(X_train, y_train, max_k):
    best_score = 0
    best_k = 0
    for k in range(1, max_k + 1):
        knn = KNeighborsClassifier(n_neighbors=k)
        scores = cross_val_score(knn, X_train, y_train, cv=5)
        if scores.mean() > best_score:
            best_score = scores.mean()
            best_k = k
    return best_k

# 示例使用
X_train = [[1, 2], [3, 4], [5, 6], [7, 8]]
y_train = [0, 1, 0, 1]
max_k = 10
optimal_k = select_optimal_k(X_train, y_train, max_k)
print("最优的K值:", optimal_k)

2. 实现

在实际编程实现中,可以使用各种编程语言和库,如Python中的scikit-learn库,它提供了KNN算法的实现。以下是使用Python实现KNN算法的详细步骤:

导入必要的库

首先,我们需要导入实现KNN所需的库,包括数据处理和模型训练所需的库。

from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
加载数据集

接下来,我们加载一个标准的数据集,例如iris数据集,用于训练和测试KNN模型。

# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
划分训练集和测试集

为了评估模型的性能,我们需要将数据集划分为训练集和测试集。

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
创建KNN模型

然后,我们创建一个KNN分类器,并设置K值。

# 创建KNN模型,设置K=3
knn = KNeighborsClassifier(n_neighbors=3)
训练模型

使用训练集数据训练KNN模型。

# 训练模型
knn.fit(X_train, y_train)
预测测试集

使用训练好的模型对测试集进行预测。

# 预测测试集
y_pred = knn.predict(X_test)
计算准确率

最后,我们计算模型的准确率,以评估模型的性能。

# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f'Accuracy: {accuracy:.2f}')

结论

KNN算法以其简单性和有效性在机器学习领域占有一席之地。通过理解其数学基础和实现步骤,我们可以更好地应用这一算法解决实际问题。随着技术的发展,KNN算法也在不断地被优化和改进,以适应更复杂的数据和应用场景。

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

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

相关文章

提升用户体验、创新产品与高效运营,企业发展三驾马车

​在当今竞争激烈的市场环境中,企业要想脱颖而出并持续发展,需同时在提升用户体验、推动产品创新以及实现内部高效运营方面下功夫。 提升用户体验至关重要。它能提高用户满意度和忠诚度,增加用户口碑与推荐,提升企业品牌形象。可通…

在 Mac(ARM 架构)上安装 JDK 8 环境

文章目录 步骤 1:检查系统版本步骤 2:下载支持 ARM 的 JDK 8步骤 3:安装 JDK步骤 4:配置环境变量步骤 5:验证安装步骤 6:注意事项步骤7:查看Java的安装路径 在 Mac(ARM 架构&#xf…

【Redis】—0.1、Ubuntu20.04源码编译部署redis6.2.7

1、Redis下载 创建redis的目录:mkdir -p /data/db/redis 下载redis:https://redis.io/download/ 2、上传文件到目录后解压 tar xvf redis-6.2.7.tar.gz 3、安装redis的依赖软件更新gcc,装一系列软件包,gcc,g和make。 s…

redis都有哪些用法

1. 缓存(Caching): • Redis常被用作缓存层,存储那些频繁访问但更新不频繁的数据,以减少数据库的访问压力,提高数据读取速度。 • LRU(Least Recently Used)淘汰策略:Red…

npm install -g@vue/cli报错解决:npm error code ENOENT npm error syscall open

这里写目录标题 报错信息1解决方案 报错信息2解决方案 报错信息1 使用npm install -gvue/cli时,发生报错,报错图片如下: 根据报错信息可以知道,缺少package.json文件。 解决方案 缺什么补什么,这里我们使用命令npm…

爬取boss直聘上海市人工智能招聘信息+LDA主题建模

爬取boss直聘上海市人工智能招聘信息 import time import tqdm import random import requests import json import pandas as pd import os from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriv…

【STM32+HAL】FreeRTOS学习小札

一、RTOS程序任务结构 如上图所示,在实时操作系统中,开发人员可以把要实现的功能划分为多个任务,每个任务负责实现其中的一部分,每个任务都是一个很简单的程序,通常是一个死循环。 二、多任务系统基本概念 1、FreeRTO…

路径规划之启发式算法之二:遗传算法(Genetic Algorithm)

遗传算法(Genetic Algorithm, GA)是一种基于自然选择和遗传学原理的优化搜索算法,它通过模拟自然界的进化过程来寻找最优解。 一、基本原理 遗传算法的基本原理是模拟自然选择、遗传和突变等生物进化过程。它通过将问题的求解过程转换成类似…

【ubuntu24.04】GTX4700 配置安装cuda

筛选显卡驱动显卡驱动 NVIDIA-Linux-x86_64-550.135.run 而后重启:最新的是12.6 用于ubuntu24.04 ,但是我的4700的显卡驱动要求12.4 cuda

Springboot的文件上传与下载

Springboot的文件上传与下载 文章说明配置路径映射实体类、服务与控制器前端页面前端服务器搭建 文章说明 文件上传实现了,文件下载是非常简单的,只需要通过浏览器即可下载成功;于是就没有实现专门的接口 配置路径映射 通过 public void addR…

多方法做配对样本t检验(三)

Wilcoxon符号秩检验 Wilcoxon符号秩检验(Wilcoxon Signed-Rank Test) 是一种非参数统计方法,用于检验两组相关样本(配对样本)之间的差异是否显著。它通常用来代替配对样本t检验,特别是在数据不符合正态分布…

如何选择最适合企业的ETL解决方案?

在今天的大数据时代,企业的数据管理和处理变得愈发重要。企业也越来越依赖于数据仓库和数据湖来提取、转换和加载(ETL)关键业务信息。一个高效、灵活的ETL解决方案不仅能提升数据处理能力,还能为企业决策提供有力支持。然而&#…

前端node.js

一.什么是node.js 官网解释:Node.js 是一个开源的、跨平台的 JavaScript 运行时环境。 二.初步使用node.js 需要区分开的是node.js和javascript互通的只有console和定时器两个API. 三.Buffer Buffer 是一个类似于数组的 对象,用于表示固定长度的字节序列。Buffer…

Facebook的开源项目解析:推动开发者社区的技术进步

Facebook,作为全球领先的社交平台之一,其在技术领域的创新不仅体现在产品功能的实现上,也积极推动开源社区的发展。开源项目已经成为Facebook技术战略的重要组成部分,通过开源,Facebook不仅加速了技术进步,…

本地学习axios源码-如何在本地打印axios里面的信息

1. 下载axios到本地 git clone https://github.com/axios/axios.git 2. 下载react项目, 用vite按照提示命令配置一下vite react ts项目 npm create vite my-vue-app --template react 3. 下载koa, 搭建一个axios请求地址的服务端 a.初始化package.json mkdir koa-server…

电阻可靠性的内容

一、影响电阻可靠性的因素: 影响电阻可靠性的因素有温度系数、额定功率,最大工作电压、固有噪声和电压系数 (一)温度系数 电阻的温度系数表示当温度改变1摄氏度时,电阻阻值的相对变化,单位为ppm/℃.电阻温…

uniapp联系我们页的设计和实现

联系我们页 代码 map文档&#xff1a;map | uni-app官网 (dcloud.net.cn) <template><view class"contact"><image class"img" src"http://www.itcast.cn/2018czydz/images/gywmban.jpg"></image><view class"…

算法竞赛进阶指南——位运算

算法竞赛进阶指南——位运算 与或非异或and&#xff0c;&or&#xff0c;|not&#xff0c;~xor&#xff0c;^ 在m位二进制数中&#xff0c;通常称最低位为第0位&#xff0c;从右到左以此类推&#xff0c;最高位是第m-1位 补码&#xff1a; unsigned int&#xff1a; 直接把…

【科研】9如何高效阅读和理解学术论文

【科研】9如何高效阅读和理解学术论文 写在最前面一、为什么需要系统的阅读方法&#xff1f;二、阅读论文的11步方法三、实践示例四、常见问题解答五、结语 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字篆刻时光&#xff0c;感谢你的陪伴与支持 ~ …

Java 泛型详细解析

泛型的定义 泛型类的定义 下面定义了一个泛型类 Pair&#xff0c;它有一个泛型参数 T。 public class Pair<T> {private T start;private T end; }实际使用的时候就可以给这个 T 指定任何实际的类型&#xff0c;比如下面所示&#xff0c;就指定了实际类型为 LocalDate…