1. KNN(K-Nearest Neighbors,K最近邻)算法简介
KNN 算法是一种监督学习算法,用于分类和回归任务。它的核心思想是:给定一个样本,找出离它最近的 K 个邻居,然后根据这些邻居的标签或数值来预测该样本的标签或数值。
2. KNN 算法的基本原理
-
训练阶段:
KNN 算法是一种懒惰学习算法,也就是说,它在训练阶段并不构建任何模型,而是直接存储训练数据。它需要的只是训练数据集。 -
预测阶段:
- 对于一个新的输入样本,KNN 会计算该样本与训练集中每个样本的距离(通常使用欧式距离、曼哈顿距离等)。
- 然后找出距离最近的 K 个样本(邻居),并根据这些邻居的标签(在分类任务中)或数值(在回归任务中)来做出预测。
- 分类任务:通过邻居的多数投票来决定新的样本的类别(最常见的类别)。
- 回归任务:通过邻居的平均值或加权平均值来预测新的样本的数值。
3. KNN 分类的过程
假设我们有一个训练数据集,每个样本都有特征和标签:
- 特征:如身高、体重、颜色等。
- 标签:如是否喜欢运动(是/否)、猫或狗等分类。
3.1 步骤:
-
选择 K 值:选择 K(一般是一个正整数),表示需要找多少个最近的邻居。K 的选择会影响分类结果,过小的 K 值可能会导致过拟合,而过大的 K 值则可能导致欠拟合。
-
计算距离:对于每个测试样本,计算它与训练集所有样本的距离。常用的距离度量方式包括:
- 欧氏距离:最常见的距离度量方法,用于计算两个样本在特征空间中的“直线”距离。 d(x,y)=(x1−y1)2+(x2−y2)2+⋯+(xn−yn)2d(x, y) = \sqrt{(x_1 - y_1)^2 + (x_2 - y_2)^2 + \cdots + (x_n - y_n)^2}d(x,y)=(x1−y1)2+(x2−y2)2+⋯+(xn−yn)2
- 曼哈顿距离:计算两个样本在特征空间中的“轴对齐”距离。 d(x,y)=∣x1−y1∣+∣x2−y2∣+⋯+∣xn−yn∣d(x, y) = |x_1 - y_1| + |x_2 - y_2| + \cdots + |x_n - y_n|d(x,y)=∣x1−y1∣+∣x2−y2∣+⋯+∣xn−yn∣
-
选取最近的 K 个邻居:计算所有训练样本与测试样本的距离,选择距离最小的 K 个训练样本。
-
分类决策:
- 分类问题:根据 K 个邻居的标签进行投票,选择最多的标签作为测试样本的预测标签。
- 回归问题:计算 K 个邻居的平均值或加权平均值,作为测试样本的预测数值。
4. KNN 算法的优点
- 简单易懂:KNN 算法直观且易于理解和实现。
- 无需训练过程:与许多其他算法(如决策树、支持向量机)不同,KNN 没有显式的训练过程,因此适用于动态数据。
- 适用于多类分类问题:KNN 算法天然适用于多类分类,不需要复杂的修改。
- 非参数算法:KNN 不做任何假设,因此不需要假设数据分布。
5. KNN 算法的缺点
- 计算开销大:KNN 在预测阶段需要计算测试样本与所有训练样本的距离,这在数据集很大的时候会非常耗时。
- 存储开销大:由于 KNN 不进行任何训练,所有数据都需要保存在内存中。
- 对噪声敏感:如果数据中有噪声,KNN 可能会错误地将噪声点作为邻居,从而影响分类结果。
- 高维数据问题(维度灾难):在高维数据中,特征之间的距离差异变得不明显,KNN 的效果会下降。
6. K 值的选择
K 值的选择非常重要,影响 KNN 的表现:
- K 太小:容易受到噪声的影响,导致过拟合。
- K 太大:可能会导致欠拟合,不能有效捕捉数据的局部模式。
通常,选择一个合适的 K 值可以通过交叉验证来完成。
7. KNN 算法的应用场景
-
分类任务:
- 图像分类:根据图像的特征找到最相似的图像进行分类。
- 文本分类:根据文档的内容特征进行分类(例如垃圾邮件分类)。
- 客户细分:根据客户的特征进行客户分类,推荐不同的服务。
-
回归任务:
- 预测房价:根据房屋的特征(如面积、位置、房龄等)预测房价。
- 股票价格预测:根据历史数据预测未来的股票价格。
8. KNN 算法的代码示例
假设我们有一个简单的二维数据集,目标是进行分类。
import matplotlib.pyplot as plt
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
# 定义样本特征数据和对应的标签
X = np.array([[1, 2], [2, 3], [3, 1], [2, 4], [6, 5], [7, 8], [8, 6], [6, 7], [7, 9], [8, 8]])
labels = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1, 1])
# 定义一个新的特征数据
X_new = np.array([[3, 5]])
# 绘制类别为0的数据,红色点
plt.scatter(X[labels == 0, 0], X[labels == 0, 1], color="red", label="Class 0")
# 绘制类别为1的数据,蓝色点
plt.scatter(X[labels == 1, 0], X[labels == 1, 1], color="blue", marker="o", label="Class 1")
# 绘制新的特征数据,绿色加号
plt.scatter(X_new[0, 0], X_new[0, 1], color="green", marker="+", label="New Point")
# 定义k值
k = 3 # 表示需要查找最近的三个邻居
# 计算新的特征数据与样本特征数据的欧氏距离
distances = [np.linalg.norm(X_new - X_) for X_ in X] # 使用np.linalg.norm计算欧式距离
print("欧氏距离:", distances)
# 查找最近的k个邻居
nearest_indices = np.argsort(distances)[:k] # 返回距离最小的k个样本的索引
print("最近的k个邻居索引:", nearest_indices)
# 根据索引获取最近邻居的标签
nearest_labels = labels[nearest_indices]
print("最近邻居的标签:", nearest_labels)
# 统计最近邻标签中出现次数最多的类别
from collections import Counter
nearest_labels = Counter(nearest_labels).most_common(1)[0][0]
print("预测类别:", nearest_labels)
# 第二种方法:
# 创建KNeighborsClassifier分类器对象
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X, labels) # 使用样本的特征和标签训Lor
new_label = knn.predict(X_new) # 预测新数据
print(new_label)
# 绘制图例和标题
plt.legend()
plt.title("KNN Visualization")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
# 显示图像
plt.show()