首页 游戏 软件 资讯 排行榜 专题
首页
AI
最近邻算法(kNN)详解

最近邻算法(kNN)详解

热心网友
60
转载
2025-07-23
本文介绍kNN算法,其通过计算不同特征值距离分类样本。以电影分类为例说明原理,还讲解用Numpy实现该算法的步骤,包括数据预处理、模型训练等,也提及超参数搜索函数,最后展示了用sklearn封装好的方法实现,以及相关笔记内容。

最近邻算法(knn)详解 - 游乐网

原理介绍

简言之,kNN算法计算不同特征值之间的距离对样本进行分类。

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

OK,说完结论,懂的可以直接看代码部分了,如果不能理解的请听我娓娓道来~现在有这么一组数据

上面6个样本(电影)分别给出其特征(打斗镜头、拥抱镜头)和标签(电影类型)信息,现在给定一个新的样本,我们想知道这部电影的类型。由于是2维数据,我们可以用平面直角坐标系表示。

最近邻算法(kNN)详解 - 游乐网        

绿色的点是未知的,红色的黄色的点是已知的。kNN要做的就是计算未知的点到所有已知点的距离,根据距离进行排序。

D谍影重重=(4957)2+(62)28.94D谍影重重=(49−57)2+(6−2)2≈8.94

D叶问3=(4965)2+(62)216.49D叶问3=(49−65)2+(6−2)2≈16.49

D我的特工爷爷=(4921)2+(64)228.07D我的特工爷爷=(49−21)2+(6−4)2≈28.07

D奔爱=(494)2+(646)260.21D奔爱=(49−4)2+(6−46)2≈60.21

D夜孔雀=(498)2+(639)252.63D夜孔雀=(49−8)2+(6−39)2≈52.63

D代理情人=(492)2+(638)256.86D代理情人=(49−2)2+(6−38)2≈56.86

排序后的数据如下,

我们在kNN算法中经常会听到说当k=3时、当k=5时...这里的k指的就是样本数。在这个例子中,当k=3时,前三个样本出现最多的电影类型是动作片,因此《这个杀手不太冷》样本也应该归为动作片。同样的,当k=5时,前5个样本出现最多的电影类型也是动作片(35>2553>52),因此样本也属于动作片。

上面提到的是2维数据,但是我们现实中处理的样本可能有3个甚至更多特征,我们无法用视觉来抽象这些特征,但是计算方法还是一样的,只不过根号里做差的数变多了而已。

最近邻算法(kNN)详解 - 游乐网        

代码实现——Numpy

机器学习算法的一般流程可以归为三步。

数据预处理加载数据交叉验证归一化模型训练模型验证

机器学习的任务就是从海量数据中找到有价值的信息, 所以在使用算法之前,我们要对数据进行预处理。

In [17]
# 1. 加载莺尾花数据集from sklearn import datasetsiris = datasets.load_iris()X = iris.datay = iris.target
登录后复制    

如果我们查看y标签信息会发现,它的前50个值为0,51—100的值为1,后50个值为2,如果直接交叉验证,取到的测试集数据可能都是label值为2的样本,这并不是我们想要的。所以在这之前,我们需要先对样本打乱顺序。zip()能将可迭代的对象打包成元组,利用 * 操作符可以将元组解压为列表。

In [18]
# 2. 实现交叉验证import numpy as npdef train_test_split(X, y, ratio=0.3):    # 乱序    data = list(zip(X, y))    np.random.shuffle(data)    X, y = zip(*data)    # 切割    boundary_X = int((1-ratio) * len(X))    boundary_y = int((1-ratio) * len(y))    # 将boundary_X和boundary_y之前的作为训练集    x_train = np.array(X[: boundary_X])    x_test = np.array(X[boundary_X:])    y_train = np.array(y[: boundary_y])    y_test = np.array(y[boundary_y:])    return x_train, x_test, y_train, y_testx_train, x_test, y_train, y_test = train_test_split(X, y)
登录后复制    

归一化主要有两种形式:0-1均匀分布和标准正态分布。

In [19]
# 3. 归一化def normalization(data):    return (data - data.min()) / (data.max() - data.min()) def standardization(data):    return (data - data.mean()) / data.std()x_train = standardization(x_train)x_test = standardization(x_test)
登录后复制    

kNN的“模型训练”有点不同于一般的模型训练过程,它们可能需要求一些参数,而kNN是计算未知点到已知点的距离。从严格意义上来说,这并不算是训练。

In [20]
# 4. 距离计算from collections import Counterclass KNNClassifier:    def __init__(self, k):        self._k = k        self._X_train = None        self._y_train = None    def fit(self, X_train, y_train):        self._X_train = X_train        self._y_train = y_train    # 预测X_predict样本的分类结果,这里的X_predict用的是交叉验证中的测试集    def predict(self, X_predict):        return np.array([self._predict(x) for x in X_predict])    def _predict(self, x):        # 计算输入样本_X_train到所有已知数据的距离        distances = np.sqrt(np.sum((self._X_train - x)**2, axis=1))        # 记录distances中前k个小的数对应的类别的出现次数        votes = Counter(self._y_train[np.argpartition(distances, self._k)[: self._k]])        # most_common(n)可以打印n个出现最多次元素的值和次数        predict_y = votes.most_common(1)[0][0]        return predict_y    # 计算准确率    def score(self, X_test, label):        y_predict = self.predict(X_test)        n_sample = len(label)        right_sample = 0        for i, e in enumerate(label):            if y_predict[i] == e:                right_sample += 1        return right_sample / n_sampleknn = KNNClassifier(k=3)knn.fit(x_train, y_train)knn.score(x_test, y_test)
登录后复制        
0.9555555555555556
登录后复制                

超参数搜索函数

kNN的参数不止是k,距离模式distype也是它的参数。对于k和distype这两种参数的组合,可能会有很多不同的结果,不妨设计一个超参数搜索函数来优化k和distype。

In [21]
class KNNClassifierSuper(KNNClassifier):    def __init__(self, k, distype):        super().__init__(k)        self.distype = distype    def _predict(self, x):        assert self.distype in ["1", "2", "3"], "Error distance type!"        if self.distype == "1":            distances = np.sum(abs(self._X_train - x), axis=1)        elif self.distype == "2":            distances = np.sqrt(np.sum((self._X_train - x)**2, axis=1))        else:            distances = np.max(abs(self._X_train - x), axis=1)        votes = Counter(self._y_train[np.argpartition(distances, self._k)[: self._k]])        predict_y = votes.most_common(1)[0][0]        return predict_y# ManhattanDistance —— "1"# EuclideanDistance —— "2"# ChebyshevDistance —— "3"for k in range(3, 15, 2):    for distype in range(1, 4):        knn = KNNClassifierSuper(k, str(distype))        knn.fit(x_train, y_train)        print("k = {}	distype = {}	score = {}".format(            k, distype, knn.score(x_test, y_test)))
登录后复制        
k = 3distype = 1score = 0.9555555555555556k = 3distype = 2score = 0.9555555555555556k = 3distype = 3score = 0.9777777777777777k = 5distype = 1score = 0.9777777777777777k = 5distype = 2score = 0.9777777777777777k = 5distype = 3score = 0.9777777777777777k = 7distype = 1score = 0.9777777777777777k = 7distype = 2score = 0.9777777777777777k = 7distype = 3score = 1.0k = 9distype = 1score = 0.9555555555555556k = 9distype = 2score = 0.9777777777777777k = 9distype = 3score = 1.0k = 11distype = 1score = 0.9777777777777777k = 11distype = 2score = 0.9555555555555556k = 11distype = 3score = 0.9777777777777777k = 13distype = 1score = 0.9777777777777777k = 13distype = 2score = 1.0k = 13distype = 3score = 0.9333333333333333
登录后复制        

代码实现——sklearn

上面我们用Numpy实现了交叉验证、归一化、距离计算等方法,这些在sklearn中都已经为我们封装好了。

In [31]
from sklearn.model_selection import train_test_split, GridSearchCVfrom sklearn import preprocessingfrom sklearn.neighbors import KNeighborsClassifier# 加载莺尾花数据iris = datasets.load_iris()X, y = iris.data, iris.target# 交叉验证x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.4)# 归一化x_train = preprocessing.scale(x_train)x_test = preprocessing.scale(x_test)# 距离计算 + 超参数搜索函数# p = 1 manhattan_distance # p = 2 euclidean_distance# arbitrary p minkowski_distance for k in range(3, 14, 2):    for p in range(1, 5):        knn = KNeighborsClassifier(n_neighbors=k, p=p)        knn.fit(x_train, y_train)        print("k = {}	p = {}	score = {}".format(            k, p, knn.score(x_test, y_test)))
登录后复制        
k = 3p = 1score = 0.9666666666666667k = 3p = 2score = 0.9833333333333333k = 3p = 3score = 0.9666666666666667k = 3p = 4score = 0.9666666666666667k = 5p = 1score = 0.9666666666666667k = 5p = 2score = 0.9833333333333333k = 5p = 3score = 0.9833333333333333k = 5p = 4score = 0.9833333333333333k = 7p = 1score = 0.9833333333333333k = 7p = 2score = 0.9833333333333333k = 7p = 3score = 0.9833333333333333k = 7p = 4score = 0.9833333333333333k = 9p = 1score = 0.9666666666666667k = 9p = 2score = 0.95k = 9p = 3score = 0.9666666666666667k = 9p = 4score = 0.9666666666666667k = 11p = 1score = 0.9666666666666667k = 11p = 2score = 0.95k = 11p = 3score = 0.9333333333333333k = 11p = 4score = 0.9333333333333333k = 13p = 1score = 0.9666666666666667k = 13p = 2score = 0.95k = 13p = 3score = 0.9166666666666666k = 13p = 4score = 0.9166666666666666
登录后复制        

笔记

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

ndarray计算的时候尽量用np的属性(np.sum()而不是sum)


ValueError: kth(=3) out of bounds (1)

计算距离的时候np.sum()需要指定axis=1,不然会直接对多维数组进行sum得到一个数值,在np.argpartition会出错。


np.sum()如果不指定axis是无法广播的,会直接返回数值
axis一种较好的理解方式是把他看成消除器。对于shape为(2L, 3L, 4L)的数组arr,np.sum(arr, axis=0)会返回shape为(3L, 4L)的数组,np.sum(arr, axis=1) 会返回shape为(2L, 4L)的数组,np.sum(arr, axis=0)会返回shape为(2L, 3L)的数组。
来源:https://www.php.cn/faq/1423593.html
免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关攻略

DeepMind之父警示:我创造的人工智能或毁灭人类,却已无法阻止
业界动态
DeepMind之父警示:我创造的人工智能或毁灭人类,却已无法阻止

3月31日消息,近日,DeepMind创始人德米斯・哈萨比斯坦言,其研发的超级人工智能存在灭绝人类的风险,而当前AI发展竞赛已进入无法停止的状态,人类难以通过外部治理手段有效管控。他彻底放弃此前依赖

热心网友
03.31
科技行业裁员潮:员工数据成AI训练关键驱动力
业界动态
科技行业裁员潮:员工数据成AI训练关键驱动力

3月31日消息,“我今天被裁员了。如果有人知道有适合我的职缺,请告诉我。谢谢!”3月,美国云端数据平台服务商Snowflake宣布裁撤整个技术写作与文档团队,约70名员工受影响。该公司资深技术文档工

热心网友
03.31
小米自研输入法系统亮相:AI智能纠错,核心能力革新。
网络安全
小米自研输入法系统亮相:AI智能纠错,核心能力革新。

3月31日消息,日前,小米向miclaw内测用户推送澎湃OS 3 Beta更新,此次版本一大亮点,是首次集成小米自研系统级输入法。从更新日志来看,该输入法将输入能力、AI能力以及系统能力深度融合,内

热心网友
03.31
中国国行苹果AI紧急上线又撤回,深夜乌龙原因曝光
网络安全
中国国行苹果AI紧急上线又撤回,深夜乌龙原因曝光

3月31日消息,今日,大量国行iPhone用户在社交平台发帖称,自己意外收到了苹果Apple Intelligence国行Beta版本推送,引发关注。据用户反馈,只需将系统升级至iOS 26 4,进

热心网友
03.31
xAI创始团队宣告结束,最后一位联合创始人已离职
业界动态
xAI创始团队宣告结束,最后一位联合创始人已离职

与SpaceX合并的人工智能初创公司xAI,近期正迎来人事的巨大变动。最新消息称,xAI创始团队中的最后一名联合创始人Ross Nordeen已在上周五离职。此前,领导xAI预训练团队的联合创始人M

热心网友
03.30

最新APP

史莱姆农场
史莱姆农场
休闲益智 03-31
凡人传说
凡人传说
角色扮演 03-30
恶魔秘境
恶魔秘境
角色扮演 03-29
猫和老鼠华为
猫和老鼠华为
休闲益智 03-29
暗黑之地
暗黑之地
角色扮演 03-28

热门推荐

Pixel 10 Pro过热致硬件损坏?用户实测长时间开手电筒风险
网络安全
Pixel 10 Pro过热致硬件损坏?用户实测长时间开手电筒风险

IT之家 3 月 31 日消息,手机手电筒是一项用户常用的功能,无论是在漆黑的衣柜里翻找物品,还是夜间在停车场辨路前行,需要时它总能随时派上用场。但如今,部分 Pixel 10 Pro 用户反馈:如

热心网友
03.31
Numbers判断闰年公式设置方法:详解步骤与实用技巧
电脑教程
Numbers判断闰年公式设置方法:详解步骤与实用技巧

闰年判定有四种Numbers兼容公式:一、MOD嵌套OR+AND逻辑;二、DATE+DAY反推2月最后一天;三、TEXT+ISERROR验证“年份-02-29”有效性;四、YEAR

热心网友
03.31
三星Hearapy应用免费上架:百赫兹音疗缓解晕车症状
科技数码
三星Hearapy应用免费上架:百赫兹音疗缓解晕车症状

IT之家 3 月 31 日消息,对很多人来说,晕车晕船是旅行中最常见的烦心事之一。三星悄然上线了一款名为 Hearapy 的免费应用,来解决这一令人不适的问题。该公司称,这款应用无需药物或物理缓解手

热心网友
03.31
湖南电信与海光信息深化合作,共筑算网融合与AI新生态
科技数码
湖南电信与海光信息深化合作,共筑算网融合与AI新生态

据海光信息(688041 SH)消息,近日,中国电信(601728 SH)湖南分公司2026年数智科技生态大会在长沙召开,中国电信湖南分公司与海光信息全面深化数智生态合作。根据协议,双方将聚焦智能制

热心网友
03.31
高端纯电困局,车企如何破解盈利难题
科技数码
高端纯电困局,车企如何破解盈利难题

30万元以上的高端纯电车,显然成了新能源车市的那块硬骨头。除了有换电加持的蔚来新ES8,大量被车企寄予厚望的高端明星纯电车都难逃疲软命运,典型如理想MEGA和i8,一次起火事故,直接造成销量断崖式下

热心网友
03.31