kNN算法

本文深入解析k-近邻算法(kNN)的工作原理、优缺点及其在电影分类预测中的应用实例。通过手动实现与sklearn库对比,展示算法的具体实现与性能表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目代码

k-NN算法介绍

kNN(k - Nearest Neighbor),中文名:k-近邻算法

工作原理:

存在一个数据集,数据集中的每个样本都有对应的标签(即该样本属于哪个类别)。当输入没有标签的新数据时,计算新数据与数据集中每个样本对应特征之间的距离之和,新数据与哪个样本距离之和最小(最近邻),就把该样本的标签作为新数据的标签。k的意思是,在实际应用中一般选取前k个与新数据距离最小的样本,在k个样本中出现最多的类别,即作为新数据的类别(标签)。

算法流程:

1. 计算新数据与数据集中每个样本对应特征之间的距离之和;
2. 将所有距离按照递增关系进行排序;
3. 选取前k个距离最小的样本;
4. 找出k个样本中出现最多的类别;
5. 将k个样本中出现最多的类别作为新数据的类别。

优点

精度高,对异常值不敏感、无数据输入假定,并且k-NN算法不知道数据的内在含义。

缺点

计算复杂度和空间复杂度高

实例:

以电影分类为示例介绍。
项目目录如图:
在这里插入图片描述

数据准备:

首先调用load_data.py模块中的load_data方法生成所需数据,可以输入参数以指定需要生成的数据量。load_data.py中的代码如下:
注:数据只是测试用,都是随机生成,不做真实参考。

import pandas as pd  # 导入pandas库
import numpy as np
import string


def load_data(nums=0):
    movies_data = [('CM', 3, 104, '爱情片'), ('HRD', 2, 100, '爱情片'), ('BW', 1, 81, '爱情片'),
                   ('KL', 101, 10, '动作片'), ('RS', 99, 5, '动作片'), ('A', 98, 2, '动作片'),
                   ]
    for _ in range(nums):
        movies_name_len = np.random.randint(2, 6)
        movies_name = ''
        for n in range(movies_name_len):
            movies_name = movies_name + string.ascii_letters[np.random.randint(1, 26)]
        fights = np.random.randint(1, 200)
        kisses = np.random.randint(1, 200)
        if fights >= kisses:
            category = '动作片'
        else:
            category = '爱情片'
        movies_data.append((movies_name, fights, kisses, category))
    df = pd.DataFrame(data=movies_data, columns=['电影名称', '打斗镜头', '接吻镜头', '电影类别'])
    df.to_csv('data/movies_data.csv', index=None)
    return df

# if __name__ == '__main__':
#     d = load_data(100)
#     print(d)

可以调用plot.py中的模块生成电影类别分布:
在这里插入图片描述

手动实现kNN代码

手写代码主要是用numpy库实现,在数据量达到上千万时,这种方式速度更快。
knn.py代码如下:

import numpy as np
import collections


def kNN(new_data, train_data, labels, k=1):
    """
    :param new_data:  新数据
    :param train_data: 训练数据
    :param labels:  训练数据的标签
    :param k:  k值大小
    :return:  新数据的所属类别
    """

    train_set_rows = train_data.shape[0]  # 计算训练数据的数据量
    subs = train_data - np.tile(new_data, (train_set_rows, 1))
    distances = np.sqrt(np.sum(np.square(subs), axis=1))  # 计算新数据与训练集每个样本之间的欧式距离

    assert distances.shape != labels.shape, '维度不一致'
    sorted_distances = np.argsort(distances)  # 对距离进行排序

    k_labels = []
    for i in range(k):
        k_labels.append(labels[sorted_distances[i]][0])  # 找出排名前k的样本类别

    new_label = collections.Counter(k_labels).most_common(1)  # 对前k个样本类别进行统计,并输出最多的类别
    return new_label[0][0]

测试及sklearn实现kNN

sklearn实现kNN操作更简单,具体方法参数,有兴趣的自行学习。

import datetime
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from load_data import *
from knn import kNN
from plot import plot


if __name__ == "__main__":
    train_set = load_data(10)
    plot(train_set)
    new_data = ['ZL', 169, 2]

    train_data = np.array(train_set[['打斗镜头', '接吻镜头']])
    train_labels = np.array(train_set[['电影类别']])

    time_s = datetime.datetime.now()
    # ===========================手动实现======================
    label = kNN(new_data[1:], train_data, train_labels, k=3)

    # ===========================sklearn实现======================
    # clf = KNeighborsClassifier(n_neighbors=3)
    # clf.fit(train_data, train_labels)
    # label = clf.predict([new_data[1:]])  # 输入是2D数据

    time_e = datetime.datetime.now() - time_s
    print('用时:', time_e)
    print('新数据的类别:', label)

### KNN算法概述 KNN(K-Nearest Neighbors,K最近邻)是一种简单却强大的分类与回归方法,在实际应用中非常常见。作为一种有监督学习算法,其核心思想是通过计算待测样本与已知样本之间的距离,找到离该样本最近的K个邻居,并依据这些邻居的信息完成预测[^1]。 --- ### KNN算法原理 KNN算法的工作机制主要分为以下几个方面: #### 距离度量 为了判断两个样本之间的相似程度,通常采用欧氏距离或其他形式的距离度量方式。对于特征空间中的两点 \(x_i\) 和 \(x_j\) ,它们之间的欧氏距离定义如下: \[ d(x_i, x_j) = \sqrt{\sum_{k=1}^{n}(x_{ik} - x_{jk})^2} \] 其中,\(n\) 表示特征维度的数量[^2]。 #### 邻居选取 选定参数 \(K\) 后,算法会从训练集中选出与当前测试样本距离最小的前 \(K\) 个样本作为“邻居”。这里的 \(K\) 是一个超参数,需根据具体应用场景调整[^3]。 #### 类别决策 在分类任务中,最终输出由这 \(K\) 个邻居共同决定。常见的策略包括投票法(多数表决)、加权投票法等。例如,当使用多数表决时,类别标签出现次数最多的即为预测结果。 --- ### KNN算法实现 以下是基于Python的一个简易版KNN分类器实现代码示例: ```python import numpy as np from collections import Counter def euclidean_distance(x1, x2): """ 计算欧几里得距离 """ return np.sqrt(np.sum((x1 - x2)**2)) class KNN: def __init__(self, k=3): self.k = k def fit(self, X_train, y_train): """ 存储训练数据 """ self.X_train = X_train self.y_train = y_train def predict(self, X_test): """ 对新数据进行预测 """ predictions = [] for test_sample in X_test: distances = [euclidean_distance(test_sample, train_sample) for train_sample in self.X_train] nearest_indices = np.argsort(distances)[:self.k] nearest_labels = [self.y_train[i] for i in nearest_indices] most_common_label = Counter(nearest_labels).most_common(1)[0][0] predictions.append(most_common_label) return predictions ``` 上述代码实现了完整的KNN流程,包括自定义欧式距离函数以及利用`Counter`模块统计频率最高的类别标签。 --- ### 性能评估与优化 在实际操作过程中,可以通过修改变量 `hoRatio` 或者调节参数 \(K\) 的大小来观察模型性能变化情况。需要注意的是,不同的数据分布可能会导致最佳配置有所不同,因此建议多次实验并记录误差率以便后续改进。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值