K 值选对,准确率翻倍:KNN 算法调参的黄金法则

article/2025/6/20 17:51:37

目录

 

一、背景介绍

二、KNN 算法原理

2.1 核心思想

2.2 距离度量方法

2.3 算法流程

2.4算法结构:

三、KNN 算法代码实现

3.1 基于 Scikit-learn 的简单实现

3.2 手动实现 KNN(自定义代码)

四、K 值选择与可视化分析

4.1 K 值对分类结果的影响

4.2 交叉验证选择最优 K 值

五、KNN 算法的优缺点与优化

5.1 优点

5.2 缺点

5.3 优化方法

六、KNN 算法的应用场景

七、KNN 与其他算法的对比

八、小结


 

一、背景介绍

K 近邻算法(K-Nearest Neighbors, KNN)是机器学习中最简单、最直观的算法之一,其核心思想源于人类对相似事物的判断逻辑 ——“近朱者赤,近墨者黑”。该算法无需复杂的训练过程,直接通过计算样本间的距离来进行分类或回归,广泛应用于图像识别、文本分类、推荐系统等领域。

二、KNN 算法原理

2.1 核心思想

KNN 的核心思想是:对于一个待预测样本,找到训练数据中与其最相似的 K 个样本(近邻),根据这 K 个样本的类别(分类问题)或数值(回归问题)进行投票或平均,从而确定待预测样本的类别或数值。

关键点

相似性度量:通过距离函数衡量样本间的相似性。

K 值选择:近邻数量 K 对结果影响显著。

投票机制:分类问题通常采用多数投票,回归问题采用均值或加权平均。

2.2 距离度量方法

常见的距离度量方法包括:

欧氏距离:适用于连续变量,计算两点间的直线距离。

曼哈顿距离:适用于城市网格路径等场景,计算两点间的折线距离。

余弦相似度:适用于文本、图像等高维数据,衡量向量间的方向相似性。

2.3 算法流程

KNN 算法的典型流程如下:

1·数据预处理:对数据进行清洗、归一化,避免特征量纲影响距离计算。

2·计算距离:计算待预测样本与所有训练样本的距离。

3·选择近邻:按距离升序排列,选取前 K 个最近邻样本。

4·分类 / 回归决策

分类:统计 K 个近邻的类别,选择出现次数最多的类别。

回归:计算 K 个近邻数值的平均值或加权平均值。

2.4算法结构:

三、KNN 算法代码实现

3.1 基于 Scikit-learn 的简单实现

以鸢尾花数据集(Iris Dataset)为例,演示 KNN 分类的完整流程。

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score# 加载鸢尾花数据集
iris = datasets.load_iris()
X = iris.data[:, :2]  # 仅取前两个特征,便于可视化
y = iris.target
feature_names = iris.feature_names[:2]# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)# 数据标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)# 创建KNN分类器(K=5)
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)# 预测测试集
y_pred = knn.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy with K=5: {accuracy:.2f}")  # 输出:Accuracy with K=5: 0.98

3.2 手动实现 KNN(自定义代码)

为深入理解算法原理,我们手动实现 KNN 分类器:

class CustomKNN:def __init__(self, n_neighbors=3):self.n_neighbors = n_neighborsdef fit(self, X_train, y_train):self.X_train = X_trainself.y_train = y_traindef predict(self, X_test):predictions = []for x in X_test:# 计算距离distances = [np.sqrt(np.sum((x - x_train)**2)) for x_train in self.X_train]# 获取最近的K个样本索引k_indices = np.argsort(distances)[:self.n_neighbors]# 获取对应的类别k_nearest_labels = self.y_train[k_indices]# 多数投票most_common = np.bincount(k_nearest_labels).argmax()predictions.append(most_common)return np.array(predictions)# 使用自定义KNN
custom_knn = CustomKNN(n_neighbors=3)
custom_knn.fit(X_train, y_train)
y_pred_custom = custom_knn.predict(X_test)
print(f"Custom KNN Accuracy: {accuracy_score(y_test, y_pred_custom):.2f}")  # 输出:0.96

四、K 值选择与可视化分析

4.1 K 值对分类结果的影响

K 值是 KNN 算法的核心超参数,其大小直接影响分类结果:

  • K 值过小:模型复杂度高,易受噪声影响,导致过拟合。
  • K 值过大:模型趋于平滑,可能忽略局部特征,导致欠拟合。

示例:在鸢尾花数据集上,不同 K 值的分类边界差异如下:

def plot_decision_boundary(clf, X, y, title, k=None):plt.figure(figsize=(8, 6))x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),np.arange(y_min, y_max, 0.02))Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])Z = Z.reshape(xx.shape)plt.contourf(xx, yy, Z, alpha=0.8)# 绘制散点图for i, color in zip([0, 1, 2], ['r', 'g', 'b']):idx = np.where(y == i)plt.scatter(X[idx, 0], X[idx, 1], c=color, label=iris.target_names[i], edgecolor='k')plt.xlabel(feature_names[0])plt.ylabel(feature_names[1])plt.title(f"KNN Decision Boundary (K={k})")plt.legend()plt.show()# K=1(过拟合)
knn1 = KNeighborsClassifier(n_neighbors=1)
knn1.fit(X_train, y_train)
plot_decision_boundary(knn1, X_test, y_test, "K=1", k=1)# K=15(欠拟合)
knn15 = KNeighborsClassifier(n_neighbors=15)
knn15.fit(X_train, y_train)
plot_decision_boundary(knn15, X_test, y_test, "K=15", k=15)

4.2 交叉验证选择最优 K 值

通过交叉验证可以有效选择最优 K 值:

from sklearn.model_selection import cross_val_score# 候选K值
k_values = range(1, 31)
cv_scores = []for k in k_values:knn = KNeighborsClassifier(n_neighbors=k)scores = cross_val_score(knn, X_train, y_train, cv=5, scoring='accuracy')cv_scores.append(scores.mean())# 绘制K值与准确率曲线
plt.plot(k_values, cv_scores, marker='o', linestyle='--', color='b')
plt.xlabel('K Value')
plt.ylabel('Cross-Validation Accuracy')
plt.title('K Value Selection via Cross-Validation')
plt.show()

五、KNN 算法的优缺点与优化

5.1 优点

简单易懂:原理直观,无需复杂数学推导。

无需训练:直接使用训练数据进行预测。

泛化能力强:对非线性数据分布有较好的适应性。

5.2 缺点

计算复杂度高:预测时需计算与所有训练样本的距离。

存储成本高:需存储全部训练数据。

对噪声敏感:K 值过小时,异常值可能显著影响结果。

5.3 优化方法

数据预处理:归一化、特征选择。

近似最近邻搜索:KD 树、球树等加速算法。

加权投票:根据距离赋予不同权重。

六、KNN 算法的应用场景

  • 图像识别与分类:常用于手写数字识别、人脸识别等任务。
  •  推荐系统:基于用户或物品的相似度进行推荐。
  •  医疗诊断:根据患者的临床指标预测疾病类别。
  •  异常检测:通过判断样本与近邻的距离识别异常点。

七、KNN 与其他算法的对比

算法核心思想优点缺点适用场景
KNN基于相似性投票 / 平均简单直观、无需训练计算慢、存储成本高、高维性能差小规模数据、实时预测
逻辑回归基于概率的线性分类训练快、可解释性强仅适用于线性可分数据、需调参二分类、概率预测
决策树基于特征划分的树结构分类可解释性强、能处理非线性数据易过拟合、对噪声敏感分类规则提取、快速预测

八、小结

KNN 算法以其简单性和直观性成为机器学习入门的经典算法,适用于小规模、低维数据的快速分类 / 回归任务。尽管存在计算效率和高维性能的局限,但其思想为许多复杂算法提供了基础。通过数据预处理、近似搜索和加权机制,KNN 的实用性可进一步提升;未来,随着硬件计算能力的提升和近似搜索算法的发展,KNN 在大规模数据中的应用可能迎来新突破。结合深度学习的特征提取能力,可构建更强大的混合模型。

 


http://www.hkcw.cn/article/iIGWQEWkAZ.shtml

相关文章

线程(上)【Linux操作系统】

文章目录 线程概念及其相关知识线程的概念及一些重要认识重要认识Linux中线程的实现Linux中的被调度的执行流是被task_struct描述的 线程是如何瓜分进程的代码和数据的?对于数据:对于代码: 线程的优点线程的缺点线程调度细节调度:…

定制开发开源AI智能名片S2B2C商城小程序:数字营销时代的话语权重构

摘要:在数据驱动的数字营销时代,企业营销话语权正从传统媒体向掌握用户数据与技术的平台转移。本文基于“数据即权力”的核心逻辑,分析定制开发开源AI智能名片S2B2C商城小程序如何通过技术赋能、场景重构与生态协同,帮助企业重构营…

【笔记】Windows 成功部署 Suna 开源的通用人工智能代理项目部署日志

#工作记录 本地部署运行截图 kortix-ai/suna: Suna - 开源通用 AI 代理 项目概述 Suna 是一个完全开源的 AI 助手,通过自然对话帮助用户轻松完成研究、数据分析等日常任务。它结合了强大的功能和直观的界面,能够理解用户需求并提供结果。其强…

哪些工作最容易被AI取代?

在 AI 技术狂飙突进的今天,一场 “职场大地震” 正在悄然酝酿。当 ChatGPT 能妙笔生花,当智能机器人开始站岗执勤,在这个 AI 飞速发展的时代,“饭碗危机” 已悄然降临。你是否想过,自己的工作是否也处在被 AI 取代的高…

二叉搜索树——AVL

AVL AVL定义AVL树出现的原因AVL的插入平衡因子的更新旋转左单旋右单旋左右双旋右左双旋 杂谈完整代码 AVL定义 AVL树是最先发明的⾃平衡⼆叉查找树,AVL是⼀颗空树,或者具备下列性质的⼆叉搜索树:它的左右⼦树都是AVL树,且左右⼦树…

Deepin 20.9社区版安装Docker

个人博客地址:Deepin 20.9社区版安装Docker | 一张假钞的真实世界 注意事项 Deepin 20.9 社区版安装 Docker 需要注意两点: 因为某些原因,Docker 官方源基本不可用,所以需要使用镜像源进行安装。当然也可以用安装包直接安装&am…

(7)-Fiddler抓包-Fiddler状态面板-QuickExec命令行

1.简介 Fiddler成了网页调试必备的工具,抓包看数据。Fiddler自带命令行控制,并提供以下用法。Fiddler的快捷命令框让你快速的输入脚本命令。 除了输入默认命令,也可以自定义命令,你可以通过编辑 FiddlerScript 来增加新命令&…

Linux --UDP套接字实现简单的网络聊天室

一、Server端的实现 1.1、服务端的初始化 ①、创建套接字&#xff1a; 创建套接字接口&#xff1a; #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int socket(int domain, int type, int protocol); //1. 这是一个创建套接字的接…

OpenHarmony标准系统-HDF框架之音频驱动开发

文章目录 引言OpenHarmony音频概述OpenHarmony音频框图HDF音频驱动框架概述HDF音频驱动框图HDF音频驱动框架分析之音频设备驱动HDF音频驱动框架分析之supportlibs实现HDF音频驱动框架分析之hdi-passthrough实现HDF音频驱动框架分析之hdi-bindev实现HDF音频驱动加载过程HDF音频驱…

C#WinForm程序时方法很多时Form.cs文件会很长,如何分别写入多个文件,partial class的作用体现出来了。

右键->添加->类 类文件名称为 FormButtonClick.cs 双击button3&#xff0c;将Form1里button3的Click事件处理方法拷贝到FormButtonClick.cs里面。

关于win10系统中环境变量path变成一行显示的问题

怎么把环境变量从一行显示恢复成列表显示(原文链接在最下面&#xff0c;感谢) 一行显示&#xff08;调整了环境变量把C:\Windows\System64开头的挪到了后面或者删了就会这样&#xff09;&#xff1a; 只需在开头加上 C:\Windows\System64; 重新打开 就恢复成列表显示了 关于wi…

NW969NW978美光闪存颗粒NW980NW984

NW969NW978美光闪存颗粒NW980NW984 技术解析&#xff1a;NW969、NW978、NW980与NW984的架构创新 美光&#xff08;Micron&#xff09;的闪存颗粒系列&#xff0c;尤其是NW969、NW978、NW980和NW984&#xff0c;代表了存储技术的前沿突破。这些产品均采用第九代3D TLC&#xf…

python打卡训练营打卡记录day41

知识回顾 数据增强卷积神经网络定义的写法batch归一化&#xff1a;调整一个批次的分布&#xff0c;常用与图像数据特征图&#xff1a;只有卷积操作输出的才叫特征图调度器&#xff1a;直接修改基础学习率 卷积操作常见流程如下&#xff1a; 1. 输入 → 卷积层 → Batch归一化层…

某航参数逆向及设备指纹分析

文章目录 1. 写在前面2. 接口分析3. 加密分析4. 算法还原5. 设备指纹风控分析与绕过 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享…

电子电器架构 --- OTA测试用例分析(上)

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…

方案精读:42页华为企业组织活力设计方案【附全文阅读】

该文档聚焦华为企业组织活力设计,核心内容为:在非线性时代,方向未必完全正确时,组织活力是企业成功关键,可通过创新与柔性激发。以熵增、熵减为理论基础,华为活力引擎模型包含宏观(厚积薄发、开放合作对抗熵增)与微观(人力资源管理对抗个人惰怠)。 实践上从三层面激活…

双目相机深度的误差分析(基线长度和相机焦距的选择)

全文基于针孔模型和基线水平放置来讨论 影响双目计算深度的因素&#xff1a; 1、基线长度&#xff1a;两台相机光心之间距离2、相机焦距&#xff08;像素&#xff09;&#xff1a; f x f_x fx​&#xff08;或 f y f_y fy​&#xff09;为焦距 f f f和一个缩放比例的乘积。在…

Namespace 命名空间的使用

名字空间&#xff1a;划分更多的逻辑空间&#xff0c;有效避免名字冲突的问题 1.什么是命名空间 名字命名空间 namespace 名字空间名 {...} // 名字空间 n1 域 namespace n1 {// 全局变量int g_money 0;void save(int money){g_money money;}void pay(int money){g_money - m…

力扣热题100之翻转二叉树

题目 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 代码 方法一&#xff1a;递归 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # …

simulink mask的使用技巧

1.mask界面布局 1.1如何调整控件的位置和控件大小&#xff1f; 反正2020a是调不了&#xff0c; 找了好久&#xff0c;只能是调布局&#xff0c;例如你要调成下面这样&#xff1a; 第一个控件的iTem location属性选择New row 后面跟着的几个和第一个同一行的空间属性选择Cu…