欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > 【机器学习】深入浅出KNN算法:原理解析与实践案例分享

【机器学习】深入浅出KNN算法:原理解析与实践案例分享

2025/2/24 5:59:51 来源:https://blog.csdn.net/weixin_41645791/article/details/145692784  浏览:    关键词:【机器学习】深入浅出KNN算法:原理解析与实践案例分享

在机器学习中,K-最近邻算法(K-Nearest Neighbors, KNN)是一种既直观又实用的算法。它既可以用于分类,也可以用于回归任务。本文将简单介绍KNN算法的基本原理、优缺点以及常见应用场景,并通过一个简单案例帮助大家快速入门。

1. KNN算法简介

KNN算法基于一个非常直观的思想:对于一个未知类别的数据点,可以通过查看它在特征空间中距离最近的K个邻居的类别或数值信息,来决定该数据点的类别或预测其值。算法的主要步骤如下:

1. 计算距离:常用的距离度量方法有欧氏距离、曼哈顿距离等。对于一个待预测的数据点,计算它与训练集中所有数据点的距离。

2. 选择最近邻:根据计算得到的距离,选取距离最小的K个数据点。

3. 决策机制

分类:采用投票机制,将待预测点归为K个邻居中出现频率最高的类别。

回归:计算K个邻居的数值平均值或加权平均值,作为预测结果。

由于KNN算法没有显式的训练过程,所以它属于一种懒惰学习(Lazy Learning)方法,即在训练阶段只存储数据,在预测时才进行计算。


2. KNN的优缺点

优点

简单易懂:KNN算法实现简单,容易理解,非常适合初学者入门机器学习。

无需训练过程:KNN不需要构建复杂的模型,直接利用存储的训练数据进行预测。

适应性强:既可以用于分类问题,也可以用于回归问题,具有较强的通用性。

缺点

计算成本高:当数据量较大时,每次预测都需要计算与所有训练样本之间的距离,计算量较大。

对噪声敏感:噪声数据或异常点可能会影响预测结果,尤其是当K值较小时。

数据不平衡问题:在类别分布不平衡的情况下,少数类可能会被多数类所掩盖,影响模型效果。


3. 应用场景

KNN算法在许多领域都有应用,包括但不限于:

手写数字识别:利用KNN对手写数字图片进行分类,实现简单而高效的数字识别。

推荐系统:基于用户相似性推荐商品或电影,利用KNN寻找兴趣相似的用户。

医学诊断:通过分析病人数据,预测疾病类别或风险值。

回归预测:例如房价预测,通过相似特征房屋的历史价格进行估值。


4. 实战案例:KNN分类

下面通过一个简单的案例,使用Python和scikit-learn库对Iris数据集进行KNN分类,帮助大家直观了解KNN的实际应用。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score# 加载Iris数据集
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分类器,设置K值为3
knn_classifier = KNeighborsClassifier(n_neighbors=3)
knn_classifier.fit(X_train, y_train)# 对测试集进行预测
y_pred = knn_classifier.predict(X_test)# 计算并输出准确率
accuracy = accuracy_score(y_test, y_pred)
print("KNN分类器在Iris数据集上的准确率:{:.2f}%".format(accuracy * 100))

运行上述代码,你将会看到KNN分类器在Iris数据集上的表现。通过调整K值或选择不同的距离度量方式,可以进一步优化模型效果。


下面给出两个案例,分别使用在线下载的数据集,演示如何用 KNN 实现分类和回归。我们分别用 OpenML 上的 Iris 数据集(分类)和 scikit-learn 内置的 California Housing 数据集(回归)来说明。

案例 1:KNN 分类(Iris 数据集)

我们通过 fetch_openml 从 OpenML 下载 Iris 数据集,然后用 KNeighborsClassifier 进行分类,并输出预测准确率。

from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score# 下载 Iris 数据集(注意:as_frame=True 会返回 Pandas DataFrame 格式)
iris = fetch_openml(name='iris', version=1, as_frame=True)
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 分类器(这里取 k=3)
knn_classifier = KNeighborsClassifier(n_neighbors=3)
knn_classifier.fit(X_train, y_train)# 对测试集进行预测
y_pred = knn_classifier.predict(X_test)# 输出分类准确率
print("KNN 分类器准确率:", accuracy_score(y_test, y_pred))

运行该代码后,会输出模型在测试集上的准确率,说明 KNN 分类器在 Iris 数据集上的表现。


案例 2:KNN 回归(California Housing 数据集)

from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsRegressor
from sklearn.metrics import mean_squared_error# 下载 California Housing 数据集
housing = fetch_california_housing(as_frame=True)
X = housing.data
y = housing.target# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 构造并训练 KNN 回归器(这里取 k=5)
knn_regressor = KNeighborsRegressor(n_neighbors=5)
knn_regressor.fit(X_train, y_train)# 对测试集进行预测
y_pred = knn_regressor.predict(X_test)# 计算并输出均方误差(MSE)
mse = mean_squared_error(y_test, y_pred)
print("KNN 回归器的均方误差:", mse)

运行该代码后,将输出模型在 California Housing 数据集上预测的均方误差,从而评估回归效果。

以上两个案例分别展示了如何利用在线数据和 scikit-learn 中的 KNN 模型进行分类和回归任务。根据具体问题的特点,可以调整 k 值、数据预处理及评估指标以获得更好的效果。


5.利用KNN算法对鸢尾花分类完整的案例:

整个流程主要包括以下几个步骤:

1. 下载和加载鸢尾花数据集

使用 scikit-learn 内置的鸢尾花数据集,可以快速获取数据,方便后续实验。

2. 案例总体处理流程

数据加载与初步探索:通过数据可视化(如散点图、成对关系图)来查看各个特征在不同类别中的分布情况,判断是否存在明显的分类边界。

数据预处理:包括数据标准化以及数据集划分。标准化能消除不同特征量纲的影响;划分为训练集和测试集,可以验证模型的泛化能力。

模型训练:利用训练集数据训练 KNN 模型。

模型评估:通过在测试集上计算准确率来评价模型性能。

模型预测:利用训练好的模型对新数据进行分类预测,并输出预测概率。

# 导入必要的库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
# 设置绘图风格
sns.set(style="whitegrid")
# 设置 Seaborn 的字体参数
sns.set(font='Heiti TC')# 1. 下载和加载鸢尾花数据集
# scikit-learn 内置的 load_iris() 函数可以直接加载数据
iris = load_iris()
# 将数据转换为 DataFrame,方便可视化探索
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
df['target'] = iris.target
# 假设 df 的列名是 iris.feature_names + ['target']
df.rename(columns={'sepal length (cm)': '萼片长度','sepal width (cm)': '萼片宽度','petal length (cm)': '花瓣长度','petal width (cm)': '花瓣宽度','target': '类别'  # 如果你也想改 target 列名的话
}, inplace=True)
print(df.head())
# 2. 数据初步探索和可视化
# 使用 Seaborn 的 pairplot 展示各特征之间的关系,颜色区分不同类别
sns.pairplot(df, hue='类别', markers=["o", "s", "D"])
plt.suptitle("鸢尾花数据各特征成对关系图", y=1.02)
plt.show()# -----------------------------
# 第3步:数据预处理——标准化 & 数据集划分
# -----------------------------# 3.1 划分训练集和测试集
# 使用 train_test_split 将数据随机拆分为训练集和测试集,这里测试集占 30%
# iris.data 表示所有特征数据,iris.target 表示对应的标签
# test_size=0.3 指定 30% 的数据作为测试集,剩余 70% 作为训练集
# random_state=22 固定随机数种子,保证每次运行结果一致
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.3, random_state=22
)# 输出数据集数量,帮助理解数据分布
print('数据总数量:', len(iris.data))       # 原始数据的样本总数
print('训练集样本数:', len(X_train))       # 训练集中包含的样本数
print('测试集样本数:', len(X_test))        # 测试集中包含的样本数# 3.2 数据标准化
# 标准化可以消除各特征之间因量纲不同带来的影响,使模型训练更稳定
scaler = StandardScaler()                   # 创建标准化转换器# 对训练集先拟合 (fit) 再转换 (transform),计算并应用均值、方差等参数
X_train_scaled = scaler.fit_transform(X_train)# 使用训练集计算得到的均值和方差,对测试集做相同的转换 (transform)
# 这里不再对测试集进行 fit,是为了避免数据泄露
X_test_scaled = scaler.transform(X_test)# -----------------------------
# 第4步:机器学习(模型训练)
# -----------------------------# 初始化 KNN 分类器,设置邻居数为3(即寻找距离最近的3个点投票决定分类)
knn = KNeighborsClassifier(n_neighbors=3)# 使用标准化后的训练集和对应的标签进行训练
knn.fit(X_train_scaled, y_train)# -----------------------------
# 第5步:模型评估
# -----------------------------# 利用训练好的模型对测试集进行预测,得到预测标签 y_pred
y_pred = knn.predict(X_test_scaled)# 计算预测结果与真实标签之间的准确率
accuracy = accuracy_score(y_test, y_pred)# 输出模型在测试集上的准确率,格式化为百分比
print("模型在测试集上的准确率:{:.2f}%".format(accuracy * 100))# -----------------------------
# 第6步:模型预测
# -----------------------------# 查看模型识别到的类别标签(这里通常是 [0, 1, 2])
print("模型识别的类别标签:", knn.classes_)# 对新数据进行预测前,必须先进行标准化转换
# 这里以两组新数据为例,每组数据包含4个特征
new_data = [[5.1, 3.5, 1.4, 0.2],[4.6, 3.1, 1.5, 0.2]
]
new_data_scaled = scaler.transform(new_data)
# 预测类别
new_pred = knn.predict(new_data_scaled)
print("新数据预测的类别:\n", new_pred)
# 预测每个类别的概率分布
new_pred_proba = knn.predict_proba(new_data_scaled)
print("新数据预测的概率分布:\n", new_pred_proba)

输出:

输出第一部分: 原始数据展示5条

输出第二部分:数据可视化

sns.pairplot(df, hue='标签', markers=["o", "s", "D"])
plt.suptitle("鸢尾花数据各特征成对关系图", y=1.02)
plt.show()

1. sns.pairplot(df, hue='target', markers=["o", "s", "D"])

• sns.pairplot:这是 Seaborn 提供的一个便捷绘图函数,可以一次性生成多张散点图和分布图,展示多个特征之间的两两关系(pairwise relationships)。

• df:这里传入的是一个包含了特征(sepal length, sepal width, petal length, petal width)以及标签列(target)的 DataFrame。

• hue='target':告诉 Seaborn 根据 target 列对数据点进行着色,这样不同类别(0, 1, 2)就会用不同颜色表示。

• markers=["o", "s", "D"]:除了颜色以外,还会用不同形状(圆圈、方形、菱形)来区分不同类别的数据点,便于区分。

2. plt.suptitle("鸢尾花数据各特征成对关系图", y=1.02)

• plt.suptitle:给整张图添加一个总标题(suptitle 表示“super title”)。

• y=1.02:将标题的位置往上移动一点,让标题不会与图像重叠。

下面我们分三个角度来解释这张成对关系图(Pairplot),帮助你从宏观到细节理解它所表达的含义:

1. Pairplot 的基本结构

1. 网格布局

• 这张图是一个 4×4 的网格,因为鸢尾花数据集有 4 个特征(萼片长度、萼片宽度、花瓣长度、花瓣宽度)。

• 每行和每列都对应一个特征,因此在网格的每个小格子里,横坐标和纵坐标分别代表这两个特征。

2. 对角线(Diagonal)

• 对角线位置的图通常是该特征的分布图(这里是核密度估计图)。

• 例如在 “萼片长度” 那个对角线小格中,你看到的是“萼片长度”在不同类别上的分布情况(曲线越高,说明在该数值范围内出现的样本越多)。

3. 非对角线(Off-diagonal)

• 对角线以外的每个小格都是一个散点图,横坐标是列对应的特征,纵坐标是行对应的特征。

• 不同颜色(以及不同形状)代表不同的类别(这里是 0、1、2 三种鸢尾花)。


2. 图中每个要素的含义

1. 散点图

• 每个点代表一条数据(一个鸢尾花样本)。

• 横纵坐标分别代表该样本在两个特征上的取值。

• 通过散点在坐标系中的分布,可以观察不同类别之间是否有明显的分隔。

2. 颜色和形状

• hue='类别' 将数据根据类别分成三种颜色(并用三种不同形状),帮助你快速区分这三类鸢尾花的分布。

• 如果在某个散点子图中,不同颜色(类别)聚成各自相对分离的簇,说明这两个特征对区分类别有帮助;如果三种颜色的点高度混杂,则这两个特征对分类的区分度不大。

3. 核密度图(对角线)

• 对角线上展示的是单一特征在三个类别上的分布情况。

• 曲线越高表示该特征在这个区间内的样本数量越多。

• 如果三个类别的曲线彼此间隔较大,说明该特征可以很好地区分这三个类别;反之,如果曲线高度重叠,说明这个特征对分类的区分度不高。


3. 如何解读这张图

1. 观察特征对分类的区分度

• 先看对角线:如果某个特征在不同类别间的分布曲线几乎不重叠,比如“花瓣长度”在类别 0(最左侧那条曲线)与 1、2 之间相差较大,就意味着“花瓣长度”对区分类别 0 与其他类别有较好的效果。

• 再看散点图:某些特征组合可能会让不同类别的点分布更明显。例如“花瓣长度”和“花瓣宽度”那一格中,如果你看到三种颜色的点几乎各自成簇,则说明这对特征组合很适合做分类。

2. 判断类别之间的重叠

• 如果在某些特征组合的散点图中,颜色分布混杂,说明这两个特征并不能很好地区分那几个类别。

• 例如,如果类别 1 和类别 2 大部分点都交织在一起,说明这两个类别在该对特征上表现相似,区分度不高。

3. 为后续建模提供参考

• 在实际的机器学习项目中,看到这样的可视化,你会知道哪些特征最能帮助你区分不同类别。

• 如果某对特征在散点图上就能把不同颜色分得很开,往往意味着它们对分类任务特别有用。


小结

这张 Pairplot 的作用:让你在一张图中同时观察所有特征两两之间的关系和分布。

图中每个格子的意义:对角线显示单一特征的分布,非对角线显示两特征间的散点分布。

如何利用:通过颜色(类别)区分,可以直观地看出某些特征(或特征组合)是否能够很好地区分不同类别。

这样,你就能从整体上把握数据特征与类别之间的关系,为后续的特征选择、模型训练和调参提供重要参考。


输出第三部分:训练与预测以及准确率

• knn.classes_ 可以查看模型内部所识别的类别(对于鸢尾花数据集,一般是三种类别 0、1、2)。

• 在实际应用中,可以使用训练好的模型对新样本进行预测,从而得到其类别标签。

通过上述详细注释,你可以清晰地了解每一步的目的、原理以及在整个机器学习流程中所扮演的角色。


6. 总结

KNN算法因其简单直观而在入门机器学习时备受推崇,虽然在大规模数据和高维数据上存在计算和噪声问题,但其易于实现和理解的特点,使其成为很多初学者和实际应用场景中的不错选择。通过本文的介绍,希望大家对KNN算法有了基本的认识,并能在实践中灵活运用。


如果你有任何问题或想进一步讨论,欢迎在评论区留言交流!

希望这篇文章能帮助你快速上手KNN算法,开启机器学习之旅。

   

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词