Lucas带你手撕机器学习——K近邻

K近邻 (K-Nearest Neighbor KNN)

K近邻算法(K-Nearest Neighbors, KNN)是一种简单直观的机器学习算法,适用于分类和回归问题。它的核心思想是:判断一个数据点的类别或预测值时,参考它在特征空间中最近的 KKK 个数据点

1. KNN 的基本原理

KNN 算法基于距离的度量来进行分类或回归。其工作方式可以用以下步骤来描述:

分类问题中的 KNN

假设我们有一些数据点,每个数据点都有一个类别,比如颜色。现在有一个新的点,我们希望知道这个点属于哪一种颜色类别。

  1. 选择 K:选择一个正整数 K,表示我们要考虑的新点周围最近的 K 个邻居点。

  2. 计算距离:计算新点与每个已有点之间的距离。常用的距离度量是欧几里得距离,公式如下:

在这里插入图片描述

其中 x 和 y 是两个数据点的特征向量。

同时有的情况也会使用曼哈顿距离公式。

在这里插入图片描述

  1. 选择最近的 K 个邻居:从已有数据中,选择与新点距离最近的 K 个点。

  2. 投票分类:统计这 K 个邻居中各个类别的数量,选择出现次数最多的类别作为新点的预测类别。

回归问题中的 KNN

在回归问题中,KNN 的原理类似,只是预测的是一个数值,而不是一个类别。

  1. 选择 K:选择一个正整数 K。
  2. 计算距离:计算新点与每个已有点之间的距离。
  3. 选择最近的 K 个邻居:选择与新点距离最近的 K 个点。
  4. 取平均值:对这 K 个邻居的数值取平均值,作为新点的预测值。

2. K 值的选择

  • 如果 K 值较小(例如 1),模型会对训练数据的噪声非常敏感,容易导致过拟合。
  • 如果 K 值较大(例如接近数据总数),模型会变得非常平滑,可能忽略细节,导致欠拟合。
  • 常见的做法是通过交叉验证选择一个合适的 K 值。

3. 使用 Scikit-Learn 实现 KNN

我们可以用 Python 的 Scikit-Learn 库实现一个简单的 KNN 示例。以下是代码示例,用于分类问题:

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score

# 生成模拟数据
np.random.seed(42)
X = np.random.rand(100, 2) * 10  # 100 个样本,2 个特征
y = (X[:, 0] + X[:, 1] > 10).astype(int)  # 简单规则:如果 x1 + x2 > 10,标记为 1,否则为 0

# 拆分数据为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建 KNN 分类器并进行训练
k = 3  # 使用 3 个最近邻居
model = KNeighborsClassifier(n_neighbors=k)
model.fit(X_train, y_train)

# 预测并计算准确率
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f'模型在测试集上的准确率: {accuracy}')

# 可视化结果
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 6))
plt.scatter(X_test[:, 0], X_test[:, 1], c=y_pred, cmap='coolwarm', marker='o', label='预测结果')
plt.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap='coolwarm', marker='x', alpha=0.5, label='真实值')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.title(f'KNN 分类结果 (K={k})')
plt.legend(loc='upper left')
plt.show()

在这里插入图片描述

4. 代码解释

  • 生成模拟数据:生成了 100 个样本,每个样本有两个特征。标签 y 是通过 x1+x2>10 来生成的二分类问题。
  • 数据集拆分:将数据集分为训练集和测试集,80% 用于训练,20% 用于测试。
  • 创建和训练模型:使用 KNeighborsClassifier 类创建 KNN 模型,并用训练集数据进行训练。
  • 预测和评估:用测试集数据进行预测,计算模型在测试集上的准确率。
  • 可视化结果:使用散点图展示测试集中数据点的预测结果和真实标签。

5. Pytorch实现KNN

import torch
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification

# 生成模拟数据
X, y = make_classification(n_samples=100, n_features=2, n_classes=2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 将数据转换为 PyTorch 张量
X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
X_test_tensor = torch.tensor(X_test, dtype=torch.float32)
y_train_tensor = torch.tensor(y_train, dtype=torch.int64)

# 定义 KNN 预测函数
def knn_predict(X_train, y_train, X_test, k=3):
    # 计算所有测试点与训练点的距离
    distances = torch.cdist(X_test, X_train)
    
    # 找到距离最近的 K 个训练点的索引
    knn_indices = distances.topk(k, largest=False).indices
    
    # 通过 K 个邻居的标签进行投票
    knn_labels = y_train[knn_indices]
    y_pred = torch.mode(knn_labels, dim=1).values
    
    return y_pred

# 使用 KNN 进行预测
k = 3
y_pred = knn_predict(X_train_tensor, y_train_tensor, X_test_tensor, k)

# 计算准确率
accuracy = (y_pred == torch.tensor(y_test)).float().mean().item()
print(f'KNN 模型在测试集上的准确率: {accuracy}')

# 可视化结果
plt.figure(figsize=(8, 6))
plt.scatter(X_test[:, 0], X_test[:, 1], c=y_pred.numpy(), cmap='coolwarm', marker='o', label='预测结果')
plt.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap='coolwarm', marker='x', alpha=0.5, label='真实值')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.title(f'KNN 分类结果 (K={k})')
plt.legend(loc='upper left')
plt.show()

代码说明

  1. 数据生成:使用 make_classification 生成二维分类数据,便于可视化。然后使用 train_test_split 将数据拆分为训练集和测试集。
  2. 数据转换:将数据转换为 PyTorch 的张量,以便后续计算。
  3. 自定义 KNN 函数
    • torch.cdist 用于计算测试集和训练集之间的欧几里得距离矩阵。
    • 使用 topk 找到距离最近的 KKK 个训练样本的索引。
    • 使用 torch.mode 进行多数投票,从而确定测试样本的预测标签。
  4. 计算准确率:比较预测值和真实标签,计算分类的准确率。
  5. 可视化结果:使用 Matplotlib 绘制预测结果与真实标签的散点图。

6. KNN 的优缺点

优点

  • 简单直观:KNN 没有复杂的训练过程,适合对模型原理的初步理解。
  • 无参数学习:KNN 是一种懒惰学习算法,不需要显式地训练模型,而是直接保存训练样本。
  • 适合小规模数据集:对于样本量小且特征不多的数据集,KNN 效果较好。

缺点

  • 计算量大:KNN 需要对每个新样本计算与所有训练样本的距离,所以在样本量大时,计算开销大。
  • 对特征尺度敏感:KNN 基于距离度量,不同尺度的特征会对距离计算产生影响,因此通常需要对特征进行标准化处理。
  • 受噪声影响大:当数据中存在噪声或异常值时,KNN 的分类结果会受到很大影响。

7. 总结

KNN 是一个基于“多数投票”思想的算法:

  • 分类:通过计算新样本与训练样本的距离,选择 KKK 个最近的邻居,选择出现次数最多的类别作为新样本的类别。
  • 回归:通过选择 KKK 个最近的邻居,取这些邻居标签的平均值作为预测值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lucas在澳洲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值