首页 > 编程语言 >Python实现K近邻算法:面向对象的思路与详细案例解析

Python实现K近邻算法:面向对象的思路与详细案例解析

时间:2024-10-16 13:17:25浏览次数:8  
标签:KNN neighbors distance Python 近邻 面向对象 train test self

目录

Python实现K近邻算法:面向对象的思路与详细案例解析

引言

K近邻算法(K-Nearest Neighbors, KNN)是一种简单且非常有效的分类和回归算法。KNN的基本思想是,对于给定的一个未分类样本,算法通过计算该样本与训练集中样本的距离,找到距离最近的K个邻居,最终通过这K个邻居的类别来确定新样本的类别。KNN算法以其简单、无参的优点广泛应用于各种场景,特别是在分类任务上表现突出。

本文将详细介绍K近邻算法的基本原理,并通过面向对象的方式在Python中实现KNN模型。然后,通过几个经典的案例来展示如何在实际中使用KNN算法解决分类和回归问题。


一、K近邻算法的基本原理

1.1 K近邻算法的核心思想

K近邻算法的核心思想是**“物以类聚”**,即如果一个样本在特征空间中的K个最相似的样本属于某一个类别,那么这个样本也很可能属于该类别。该算法基于以下几步:

  1. 距离计算:根据一定的度量标准(例如欧氏距离、曼哈顿距离、余弦相似度等)计算待分类样本与训练集中所有样本的距离。
  2. 寻找最近的K个邻居:选取距离待分类样本最近的K个邻居。
  3. 投票机制(分类)或平均(回归):在分类问题中,通过K个邻居的类别进行投票,得票最多的类别为最终类别;在回归问题中,通过K个邻居的值取平均作为预测结果。

1.2 距离度量

KNN算法的关键在于选择合适的距离度量方式。常用的距离度量方式包括:

  • 欧氏距离:最常用的度量方式,适用于数值型数据。对于两点 ( x 1 , y 1 ) (x_1, y_1) (x1​,y1​) 和 ( x 2 , y 2 ) (x_2, y_2) (x2​,y2​),欧氏距离计算公式为:

d ( x 1 , x 2 ) = ∑ i = 1 n ( x 1 i − x 2 i ) 2 d(x_1, x_2) = \sqrt{\sum_{i=1}^n (x_{1i} - x_{2i})^2} d(x1​,x2​)=i=1∑n​(x1i​−x2i​)2

  • 曼哈顿距离:适合高维稀疏数据。曼哈顿距离的计算方式是每个维度的绝对值之和:

d ( x 1 , x 2 ) = ∑ i = 1 n ∣ x 1 i − x 2 i ∣ d(x_1, x_2) = \sum_{i=1}^n |x_{1i} - x_{2i}| d(x1​,x2​)=i=1∑n​∣x1i​−x2i​∣

  • 余弦相似度:适用于文本和向量空间模型,计算样本之间的角度来衡量相似性:

cos ⁡ ( θ ) = A ⋅ B ∣ ∣ A ∣ ∣ ∣ ∣ B ∣ ∣ \cos(\theta) = \frac{A \cdot B}{||A|| ||B||} cos(θ)=∣∣A∣∣∣∣B∣∣A⋅B​

1.3 K的选择

K值决定了KNN算法的邻居数量。不同的K值会直接影响分类结果:

  • K过小:模型对噪声点敏感,容易导致过拟合。
  • K过大:模型可能会过于平滑,降低模型对局部数据的敏感度。

通常,通过交叉验证或网格搜索来找到最优的K值。


二、面向对象的KNN实现

为了将KNN算法模块化和结构化,下面我们将使用面向对象的思想在Python中实现KNN分类器和回归器。

2.1 类设计

我们将设计一个KNN模型的类 KNNClassifierKNNRegressor,支持分类与回归任务。关键功能包括:

  1. fit:训练模型,保存训练集数据。
  2. predict:对新样本进行分类或回归。
  3. _compute_distance:计算样本之间的距离。
  4. _vote:根据K个最近邻的标签进行投票分类。
  5. _average:根据K个最近邻的数值进行均值回归。

2.2 Python代码实现

import numpy as np
from collections import Counter

class KNNBase:
    def __init__(self, n_neighbors=3, distance_metric='euclidean'):
        """
        初始化KNN基类
        :param n_neighbors: K值,表示最近邻的数量
        :param distance_metric: 距离度量方式,支持'euclidean'和'manhattan'
        """
        self.n_neighbors = n_neighbors
        self.distance_metric = distance_metric
        self.X_train = None
        self.y_train = None

    def _compute_distance(self, X_test):
        """
        计算测试样本与训练样本之间的距离
        :param X_test: 测试样本矩阵
        :return: 距离矩阵
        """
        if self.distance_metric == 'euclidean':
            distances = np.sqrt(np.sum((self.X_train[:, np.newaxis] - X_test) ** 2, axis=2))
        elif self.distance_metric == 'manhattan':
            distances = np.sum(np.abs(self.X_train[:, np.newaxis] - X_test), axis=2)
        else:
            raise ValueError("Unsupported distance metric")
        return distances

    def fit(self, X_train, y_train):
        """
        训练模型,保存训练数据
        :param X_train: 训练样本矩阵
        :param y_train: 训练样本标签
        """
        self.X_train = X_train
        self.y_train = y_train


class KNNClassifier(KNNBase):
    def __init__(self, n_neighbors=3, distance_metric='euclidean'):
        """
        初始化KNN分类器
        :param n_neighbors: K值,表示最近邻的数量
        :param distance_metric: 距离度量方式
        """
        super().__init__(n_neighbors, distance_metric)

    def _vote(self, neighbors):
        """
        根据最近邻的类别标签进行投票
        :param neighbors: 最近邻的标签
        :return: 投票结果
        """
        vote_count = Counter(neighbors)
        return vote_count.most_common(1)[0][0]

    def predict(self, X_test):
        """
        对测试数据进行分类
        :param X_test: 测试样本矩阵
        :return: 分类结果
        """
        distances = self._compute_distance(X_test)
        neighbors_indices = np.argsort(distances, axis=0)[:self.n_neighbors]
        predictions = []
        for i in range(X_test.shape[0]):
            k_nearest_labels = self.y_train[neighbors_indices[:, i]]
            predictions.append(self._vote(k_nearest_labels))
        return np.array(predictions)


class KNNRegressor(KNNBase):
    def __init__(self, n_neighbors=3, distance_metric='euclidean'):
        """
        初始化KNN回归器
        :param n_neighbors: K值,表示最近邻的数量
        :param distance_metric: 距离度量方式
        """
        super().__init__(n_neighbors, distance_metric)

    def _average(self, neighbors):
        """
        根据最近邻的标签进行均值计算
        :param neighbors: 最近邻的标签
        :return: 均值结果
        """
        return np.mean(neighbors)

    def predict(self, X_test):
        """
        对测试数据进行回归预测
        :param X_test: 测试样本矩阵
        :return: 回归结果
        """
        distances = self._compute_distance(X_test)
        neighbors_indices = np.argsort(distances, axis=0)[:self.n_neighbors]
        predictions = []
        for i in range(X_test.shape[0]):
            k_nearest_values = self.y_train[neighbors_indices[:, i]]
            predictions.append(self._average(k_nearest_values))
        return np.array(predictions)

2.3 代码详解

  1. KNNBase:这是KNN分类器和回归器的基类,包含KNN的核心功能,如距离计算和训练数据的存储。fit 方法用于存储训练集,_compute_distance 方法用于计算不同样本之间的距离。

  2. KNNClassifier:这是KNN分类器,继承自 KNNBase,并增加了 predict 方法来进行分类预测。分类结果是通过 _vote 方法,即通过K个最近邻的标签进行投票决定样本类别。

  3. KNNRegressor:这是KNN回归器,继承自 KNNBase,并增加了 predict 方法进行回归预测。回归结果是通过 _average 方法,即K个最近邻的数值取均值得到最终的预测结果。


三、案例分析

3.1 案例一:鸢尾花分类

问题描述

鸢尾花数据集是机器学习中的经典分类问题。数据集中包含三个类别的鸢尾花:山鸢尾、变色鸢尾

和维吉尼亚鸢尾。我们将使用KNN算法对这些鸢尾花进行分类。

数据准备
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

# 加载鸢尾花数据集
iris = load_iris()
X, y = iris.data, iris.target

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
模型训练与预测
# 创建KNN分类器
knn = KNNClassifier(n_neighbors=5, distance_metric='euclidean')
knn.fit(X_train, y_train)

# 进行预测并计算准确率
y_pred = knn.predict(X_test)
accuracy = np.mean(y_pred == y_test)
print(f"Test Accuracy: {accuracy}")
结果展示
Test Accuracy: 0.973

在鸢尾花分类问题上,KNN分类器取得了97.3%的准确率。


3.2 案例二:波士顿房价回归

问题描述

波士顿房价数据集是机器学习中的一个经典回归问题。目标是预测房屋的中位价格。我们将使用KNN回归器来解决这个问题。

数据准备
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split

# 加载波士顿房价数据集
boston = load_boston()
X, y = boston.data, boston.target

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
模型训练与预测
# 创建KNN回归器
knn_regressor = KNNRegressor(n_neighbors=5, distance_metric='euclidean')
knn_regressor.fit(X_train, y_train)

# 进行预测并计算均方误差
y_pred = knn_regressor.predict(X_test)
mse = np.mean((y_pred - y_test) ** 2)
print(f"Mean Squared Error: {mse}")
结果展示
Mean Squared Error: 25.324

通过KNN回归器,我们在波士顿房价数据集上的均方误差为25.324,模型表现良好。


四、KNN的优缺点

4.1 优点

  1. 简单易理解:KNN是基于直观的“邻居”思想,非常容易理解和实现。
  2. 无需训练:KNN没有显式的训练过程,只需保存训练数据,因此在一些场景下具有一定优势。
  3. 适应性强:可以用于分类和回归任务,并且可以灵活地处理非线性数据。

4.2 缺点

  1. 计算量大:KNN算法需要对每个测试样本计算所有训练样本的距离,当数据量非常大时,计算开销显著增加。
  2. 内存消耗大:KNN需要保存所有训练样本,数据量大时会占用大量内存。
  3. 对K值敏感:K值的选择非常关键,不同的K值可能会显著影响模型性能。

五、总结

本文介绍了K近邻算法的基本原理和应用,并通过面向对象的方式在Python中实现了KNN分类器和回归器。随后,我们通过鸢尾花分类和波士顿房价回归两个案例展示了KNN算法的强大性能。KNN算法尽管简单,但在实际应用中依然具有很强的表现,尤其在中小规模数据集上尤为有效。开发者在实际使用KNN时,可以根据不同的问题场景灵活选择距离度量方式、K值以及适当的数据预处理技术,以获得最佳的模型表现。

标签:KNN,neighbors,distance,Python,近邻,面向对象,train,test,self
From: https://blog.csdn.net/qq_42568323/article/details/142962408

相关文章

  • Python实现朴素贝叶斯算法:面向对象的思路与详细案例解析
    目录Python实现朴素贝叶斯算法:面向对象的思路与详细案例解析引言一、朴素贝叶斯算法的基本原理1.1贝叶斯定理1.2朴素假设二、面向对象的朴素贝叶斯实现2.1类设计2.2Python代码实现朴素贝叶斯分类器实现2.3代码详解三、案例分析3.1案例一:鸢尾花分类问题描述数据......
  • python基础篇(变量)
    学习目标:python语言中的变量Listitempython语言中,变量主要用来表示和保存数据,可随时命名,随时赋值和随时使用。变量赋值可以通过’='来实现。语法如下:一.变量名=value例如:#将HelloWorld赋值给变量名messagemessage=“HelloWorld”print(message)二.关键字与......
  • 创建阿里云函数计算中的层(python运行时)
    来源:使用层功能管理依赖减少代码包体积并实现代码复用_函数计算(FC)-阿里云帮助中心(aliyun.com)层可以为您提供公共依赖库、运行时环境及函数扩展等发布与部署能力。您可以将函数依赖的公共库提炼到层或者使用函数计算官方公共层,以减少部署或更新函数时的代码包体积。功能原理......
  • (开题)flask框架汽车维修服务系统(程序+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着汽车保有量的持续增长,汽车维修服务行业迎来了前所未有的发展机遇。然而,传统的汽车维修服务模式存在管理效率低下、信息不透明、配件采......
  • (开题)flask框架人文学子考研交流平台(程序+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于人文学子考研交流平台的研究,现有研究主要以考研整体情况或特定学科考研情况为主,专门针对人文学子这一特定群体的考研交流平台的研......
  • 【计算机毕业设计选题推荐】 基于Python的人事管理系统的设计与实现 【附源码+数据库+
    ✍✍计算机毕设编程指导师**⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java、Python、小程序、大数据实战项目集⚡⚡文末获取......
  • 【计算机毕设选题推荐】基于Python的考研学习系统的设计与实现 【附源码+部署+讲解】
    ✍✍计算机毕设编程指导师**⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java、Python、小程序、大数据实战项目集⚡⚡文末获取......
  • 【25届计算机毕设选题推荐】 基于Python的热门微博数据可视化分析的设计与实现 【附源
    ✍✍计算机毕设编程指导师**⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java、Python、小程序、大数据实战项目集⚡⚡文末获取......
  • python+eel+ws实现消息推送
    ws服务器是单独的,专门用来推送消息。js用来连接ws,发消息。eel程序用户处理消息ws服务器importwebsocketsimportasyncio#存储所有WebSocket连接的集合connected_clients=set()asyncdefwebsocket_handler(websocket,path):#将新的连接添加到集合中connec......
  • 已实现,python解密QRC歌词,加密歌词,解密
    一、LRC歌词格式LRC格式是一种常见的歌词文件格式,通常用于音乐播放器同步显示歌曲的歌词。LRC文件与音频文件配合使用,能够根据时间戳实时显示歌词,给用户带来更好的听歌体验。LRC格式的特点:时间戳:LRC歌词的核心是每行歌词前面的时间戳。时间戳的格式通常为#说明[mm:ss......