机器学习——K-近邻算法(KNN)
机器学习——K-近邻算法(KNN)
一、KNN算法简介
K-近邻算法(K-Nearest Neighbors, 简称 KNN)是一种基于实例的机器学习算法,广泛应用于分类和回归任务。它通过计算数据点之间的相似度(通常是距离度量),然后预测新的数据点的标签或数值。
KNN 的核心思想非常直观:“一个样本的类别(或数值)取决于其最邻近的 k 个邻居的类别(或数值)。”
二、KNN 的基本流程
1. 工作原理
KNN 的流程可以分为以下几个步骤:
数据准备:将数据划分为训练集和测试集。
计算距离:
- KNN 通过计算待预测样本与所有训练样本之间的距离来找到最邻近的样本。常见的距离度量方法包括欧几里得距离、曼哈顿距离、余弦相似度等。
- 选择 k 值:
- k 是一个超参数,表示选择多少个最近邻居来进行投票或计算均值。合理选择 k 值对于 KNN 的表现至关重要。
- 预测:
对于分类问题,KNN 使用多数投票原则,根据 k 个最近邻居的类别进行投票,选出出现最多的类别。
对于回归问题,KNN 使用均值或加权均值,将 k 个邻居的值进行平均或加权平均,得到预测值。
- 输出结果:预测测试样本的类别或数值。
┌───────────────┐
│ 训练数据集 │
└───────────────┘
↓
┌───────────────────┐
│ 测试样本与训练样本 │
│ 计算距离(如欧几里得) │
└───────────────────┘
↓
┌──────────────────────────┐
│ 选择距离最近的 k 个邻居 │
└──────────────────────────┘
↓
┌──────────────────────────┐
│ 分类:多数表决或加权表决 │
│ 回归:均值或加权平均值 │
└──────────────────────────┘
↓
┌─────────────┐
│ 输出预测结果 │
└─────────────┘
2.KNN 的核心要素
常见距离度量方法
距离的计算是 KNN 的关键,常用方法有:
- 欧几里得距离(最常见):
应用场景:特征间没有显著相关性的连续数据。
- 曼哈顿距离:
应用场景:特征是离散或格点数据。
- 余弦相似度(主要用于文本向量):
应用场景:文本向量、稀疏向量。
超参数 k 的选择
k太小:容易受到噪声影响,导致过拟合。
k太大:邻居中远处的数据可能掩盖局部信息,导致欠拟合。
示例:以下图展示了 k=1 和 k=5 的分类效果。
三、KNN 的优缺点
优点 缺点
简单直观,易于实现。 计算复杂度高:每次预测需要计算与所有训练样本的距离。
无需显式训练阶段,适合小规模数据。 内存消耗大:存储所有训练数据。
能够处理多分类问题。 高维问题效果差:距离计算在高维数据中不再可靠(维度灾难)。
对噪声敏感,数据预处理要求高。
四、KNN理论与图示
1.分类示例:二维平面数据
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.neighbors import KNeighborsClassifier
# 生成数据集
X, y = make_blobs(n_samples=200, centers=2, cluster_std=1.0, random_state=42)
# 可视化数据分布
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', s=30)
plt.title("二维分类数据分布")
plt.xlabel("特征1")
plt.ylabel("特征2")
plt.show()
# 定义KNN模型
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X, y)
# 绘制决策边界
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1))
Z = knn.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.8, cmap='coolwarm')
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', s=30, edgecolor='k')
plt.title("KNN 分类决策边界 (k=3)")
plt.xlabel("特征1")
plt.ylabel("特征2")
plt.show()
2.回归示例:一维曲线拟合
from sklearn.neighbors import KNeighborsRegressor
from sklearn.metrics import mean_squared_error
# 生成一维回归数据
np.random.seed(42)
X = np.sort(5 * np.random.rand(40, 1), axis=0)
y = np.sin(X).ravel() + np.random.normal(0, 0.2, X.shape[0])
# 定义 KNN 回归器
knn_reg = KNeighborsRegressor(n_neighbors=5)
knn_reg.fit(X, y)
# 预测
X_test = np.linspace(0, 5, 100).reshape(-1, 1)
y_pred = knn_reg.predict(X_test)
# 可视化回归结果
plt.scatter(X, y, color='darkorange', label='训练数据')
plt.plot(X_test, y_pred, color='navy', label='KNN 回归 (k=5)')
plt.title("KNN 回归示例")
plt.xlabel("特征值")
plt.ylabel("目标值")
plt.legend()
plt.show()
五、KNN 算法的超参数优化
选择 k值:
k 过小:模型容易过拟合,噪声对分类结果影响大。
k 过大:模型容易欠拟合,决策边界变得过于平滑。
优化方法:
通过交叉验证选取最佳 k值。
一般从 k=1 开始尝试逐步增大,选取在验证集上准确率最高的值。
距离度量方法:
欧几里得距离适合连续数据。
曼哈顿距离适合离散数据。
余弦相似度适合高维稀疏数据。
优化方法:
- 测试不同的距离度量,选择验证集上效果最好的方法。
加权策略:
给近邻赋予更高的权重(如距离的倒数),以增强其影响力。
或者通过网格搜索测试均等权重和距离权重的效果。
六、Python实例展示:使用KNN预测鸢尾花分类
1.问题描述
我们将使用 KNN 算法对著名的鸢尾花数据集进行分类任务。目标是根据花的特征(如花瓣长度和宽度)预测其类别。
鸢尾花根据其特征分Setosa,Versicolor,Virginica三个类别。
2.代码
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
import matplotlib.pyplot as plt
import numpy as np
# 加载鸢尾花数据集
iris = load_iris()
X = iris.data[:, :2] # 只选择前两个特征(花萼长度和花萼宽度)用于可视化
y = iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 创建 KNN 模型
k = 5 # 设置最近邻的数量
knn = KNeighborsClassifier(n_neighbors=k)
# 模型训练
knn.fit(X_train, y_train)
# 模型预测
y_pred = knn.predict(X_test)
# 输出准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"KNN 模型准确率: {accuracy:.2f}")
# 创建网格以绘制决策边界
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1))
# 预测网格点类别
Z = knn.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# 绘制决策边界
plt.contourf(xx, yy, Z, alpha=0.8, cmap='coolwarm')
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', edgecolor='k')
plt.title(f"KNN 决策边界 (k={k})")
plt.xlabel("花萼长度 (cm)")
plt.ylabel("花萼宽度 (cm)")
plt.show()
七、实际应用场景
1. 图像分类
在图像分类任务中,KNN 可以通过计算图像特征向量之间的距离来分类,例如手写数字识别。
2. 文本分类
KNN 可用于垃圾邮件检测,通过比较新邮件和历史邮件的相似性,判断其类别。
3. 推荐系统
基于用户相似度的推荐系统中,KNN 常用于查找兴趣相似的用户群体。