(CS231n课程笔记)深入探讨 k最近邻算法(KNN算法)

目录

k-近邻算法(k-Nearest Neighbors, k-NN)

算法详解

kNN算法优缺点分析

计算复杂度分析

kNN算法的实现


k-近邻算法(k-Nearest Neighbors, k-NN)

k-近邻算法(k-NN) 是分类算法中最简单的算法之一,可用于图像分类,实际中极少使用。主要方法就是找到你的邻居作为你的分类标签。计算机不像人的眼睛,无法直接对比出相像的分类,因此引出

KNN最邻近分类算法的实现原理:判断未知样本的类别,以所有已知类别的样本作为参照,计算未知样本与所有已知样本的距离,从中选取与未知样本距离最近的K个已知样本,根据少数服从多数的投票法则(majority-voting),将未知样本与K个最邻近样本中所属类别占比较多的归为一类。

算法详解

 如何对图像进行分类或如何计算图像的距离呢?最简单的方法就是将图像用像素值对应的矩阵来表示,将样本与测试集逐个像素比较,最后将差异值全部加起来。就是将两张图片先转化为两个向量I_{1}I_{2},然后对他们进行计算,流程如下图,

上面这个计算结果就叫L1距离:

两张图片使用L1距离来进行比较。逐个像素求差值,然后将所有差值加起来得到一个数值。如果两张图片一模一样,那么L1距离为0,但是如果两张图片很是不同,那L1距离将会非常大。

另外还有L2距离:

两个距离没有好坏之分,实际运用时最好都试试,选效果最好的距离。一般来说,特征有明确含义时用L1,没有明确含义用L2

 选择最近邻:根据计算的距离,选择距离最近的 k个训练样本,将它们作为最近邻样本。 在图像分类任务中, k 个最近邻的类别中占比最多的类别作为预测结果。kNN算法没有训练过程,在预测过程中进行计算得出结果,而我们想要的是训练过程可以长,预测要快,所以knn算法是不好的。

k-NN分类器需要选择设定k值,选择使用哪种距离计算,所有这些选择,被称为超参数。超参数如何选择,我们可以尝试选取不同的值,哪个值表现好就用哪个。这个链接直接体验超参数不同的影响:vision.stanford.edu/teaching/cs231n-demos/knn/

从直观感受上就可以看到,更高的k值可以让分类的效果更平滑,使得分类器对于异常值更有抵抗力,泛化能力更好了。 K值选的太大易引起欠拟合,太小容易过拟合,需交叉验证确定K值。

kNN算法优缺点分析

  • 优点

    • 简单易实现:k-NN 是最直观、最简单的分类算法之一,无需显式的训练过程。
    • 无参数模型:k-NN 不需要通过参数调整来学习模型,仅依赖训练数据本身。
    • 适应性强:k-NN 可以处理多种类型的数据,只需更改距离度量方式即可。
  • 缺点

    • 计算复杂度高:对于每个新样本,k-NN 需要计算其与所有训练样本的距离,这在大数据集上非常耗时。时间复杂度为 O(n×d)。
    • 内存消耗大:必须存储所有训练数据,导致内存消耗高,空间复杂度为 O(n×d)。
    • 对噪声数据敏感:k-NN 直接使用所有训练样本,噪声样本可能对分类结果产生显著的负面影响。
    • 维度灾难:随着特征维度的增加,样本之间的距离变得更加难以区分,导致算法性能下降。例如一些处理过后的图片,人眼看上去可能有很大不同,但是计算出的距离和未处理过的图片的距离是相同的。

 

 

        

计算复杂度分析

  • 时间复杂度

    • 训练阶段:k-NN 没有显式的训练阶段,时间复杂度为 O(1)。
    • 测试阶段:对于每个测试样本,k-NN 需要计算它与所有训练样本的距离。时间复杂度为 O(n×d),其中 n是训练样本的数量,d是特征的维度。
  • 空间复杂度

    • 需要存储所有训练样本,空间复杂度为 O(n×d)。

kNN算法的实现

我们用k-最近邻算法(k-NN)对 CIFAR-10 图像数据集进行分类。CIFAR-10 是一个常用的图像分类数据集,包含 60000 张 32x32 像素的彩色图像,分为 10 个类别。代码实现了从数据预处理到模型训练和评估的整个流程。具体代码如下:

import numpy as np
from tensorflow.keras.datasets import cifar10
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
from skimage.transform import resize

# Step 1: 加载CIFAR-10数据集
(X_train_full, y_train_full), (X_test_full, y_test_full) = cifar10.load_data()

# Step 2: 从训练集中选择1000个样本,从测试集中选择200个样本
X_train, _, y_train, _ = train_test_split(X_train_full, y_train_full, train_size=1000, random_state=42, stratify=y_train_full)
X_test, _, y_test, _ = train_test_split(X_test_full, y_test_full, train_size=200, random_state=42, stratify=y_test_full)

# Step 3: 数据预处理
# 将图片缩放为8x8,并展平成一维向量
X_train = np.array([resize(image, (8, 8)).flatten() for image in X_train])
X_test = np.array([resize(image, (8, 8)).flatten() for image in X_test])

# 缩放像素值至 [0, 1] 范围
X_train = X_train / 255.0
X_test = X_test / 255.0

# 将标签转为一维
y_train = y_train.flatten()
y_test = y_test.flatten()

# Step 4: 标准化特征
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# Step 5: 创建并训练k-NN分类器
knn = KNeighborsClassifier(n_neighbors=3, metric='euclidean')  # 使用欧氏距离,k值为3
knn.fit(X_train, y_train)

# Step 6: 对测试集进行预测
y_pred = knn.predict(X_test)

# Step 7: 评估模型性能
accuracy = accuracy_score(y_test, y_pred)
print(f"测试集上的准确率为: {accuracy:.4f}")

为了减小计算复杂度,我进行了图像缩放,将 32x32 的图像缩放为 8x8,并展平成一维向量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值