ML算法——KNN随笔【全国科技工作者日创作】【机器学习】

news/2024/11/30 9:39:52/

9、K-Nearest Neighbors (KNN)

9.1、理论部分

K最邻近算法

  • 把一个物体表示成向量【特征工程】,且 KNN 需要考虑 【特征缩放】。
  • 标记每个物体的标签
  • 计算两个物体之间的距离/相似度
  • 选择合适的 K

未知点的判断基于已知点的距离,选出最近的K个点,投票选出未知点的最大可能。

计算两个物体之间的距离/相似度?

欧氏距离

∑ i = 1 n ( x i − x i ) 2 \sqrt{\sum_{i=1}^{n}(x_i^{} - x_i^{})^2} i=1n(xixi)2

其中,xi和xj是空间中的两个点,i和j表示维度。

点数K选取奇数的目的?

偶数更容易出现“平票”,奇数也不可避免地会出现平票(1:1:1)

使用 sklearn 实现,详见9.3。

选择合适的 k 对决策边界的影响?

决策边界:决定线性分类器、非线性分类器。

在这里插入图片描述

图中:

  • 线性
  • 非线性
  • 非线性【最陡峭】,过拟合。

KNN的决策边界举例:

在这里插入图片描述

边界越陡峭,越不稳定,希望得到平滑的边界,理论上,K↑,边界越平滑。

如何选择 K 值?

交叉验证:训练集进一步划分为训练集【train】+验证集【validation】

以常用的五折交叉验证为例,

在这里插入图片描述

  • 对 K= 1执行五次循环,取平均,作为 k= 1的成绩。

  • 换 K ,重复。

  • 千万不能用测试数据【X_test、y_test】来调参

在数据少时,可适当增加折数的合理性?

交叉验证可以通过增加折数来减少主观因素的影响,使得结果更加准确。

主观因素:主要指在进行数据分割的时候,因为某些人为因素导致分割不准确,进而对结果产生影响。比如,如果使用随机拆分数据的方式进行验证,因为随机拆分数据的时候存在不随机的情况,所以就会对验证效果产生影响。

KNN的优化方向

  • 时间复杂度 O(N),适合低维空间内使用,优化方向:KD-tree 在二维空间的优化、LSH(Locality Sensitivity Hashing)不再寻求完全准确的解,加快搜索。
  • 特征间的相关性处理,Mahalanobis Distance
9.2、实现
9.2.1、KNN 手写实现
from sklearn import datasets
from collections import Counter # 投票
from sklearn.model_selection import train_test_split
import numpy as npdef euc_dis(instance1, instance2):"""计算欧氏距离:param instance1:样本1,array数组:param instance2: 样本2,array数组:return: 欧氏距离"""d = np.sqrt(sum(instance1-instance2)**2)return ddef knn_classify(X , y, testInstance, k):"""给未知点归类:param X: train——feature:param y: train——label:param testInstance:测试数据,array数组:param k:选择多少个 neighbors:return:最多元素"""distances = [euc_dis(x, testInstance)for x in X]kneighbors = np.argsort(distances)[:k] #快排后,取前 k 个  || 优化?改用优先队列,维护前 k 个, O(NlogN)count = Counter(y[kneighbors]) # Counter([0,0,0,1,1,1,1,1,1])  -》 Counter({1: 6, 0: 3})return count.most_common()[0][0]   # [(1, 6), (0, 3)]  -》 1#导入 iris 数据
iris = datasets.load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=50)#预测结果
predictions = [knn_classify(X_train, y_train, data, 3) for data in X_test]
correct = np.count_nonzero((predictions == y_test) == True)
# acc
print("Accuaracy is :%.3f" %(correct/len(X_test)))
9.2.2、KNN sklearn 实现

鸢尾花【三分类问题

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

读取数据 X,y

data = datasets.load_iris()
X = data.data   #N*D:sample * Dimension
y = data.target #label:(0,1,2)

分为训练数据 & 测试数据 (默认比例: 3/4 : 1/4)

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=500)

构建KNN模型,K=3 & 训练

clf = KNeighborsClassifier(n_neighbors=3)
clf.fit(X_train, y_train)

计算准确率(二选一)

方法一

from sklearn.metrics import accuracy_scoreacc  = accuracy_score(y_test,clf.predict(X_test))
print(acc)

方法二

import  numpy as npcorrect = np.count_nonzero((clf.predict(X_test) == y_test) == True)
print(f'acc is {correct/len(X_test)}')

完整代码

#
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
#
data = datasets.load_iris()
X = data.data   #N*D:sample * Dimension
y = data.target #label:(0,1,2)
#
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=500)
#
clf = KNeighborsClassifier(n_neighbors=3)
clf.fit(X_train, y_train)
#
from sklearn.metrics import accuracy_scoreacc  = accuracy_score(y_test,clf.predict(X_test))
print(acc)

KNN没有训练痕迹,那么 clf.fit() 在做什么?

它是机器学习中唯一一个不需要训练过程的算法,它在训练阶段只是把数据保存下来,训练时间开销为 0,等收到测试样本后进行处理。

knn 算法手写实现的意义?较 sklearn 实现的 knn 优势在哪里?

  1. 简单易理解:KNN算法非常简单,易于理解。通过自己实现该算法,可以更深入地了解KNN算法的工作原理。
  2. 可扩展性:自己实现KNN算法可以让你更好地了解如何扩展算法以适应不同的数据集和场景。例如,你可以尝试使用不同的距离度量(如曼哈顿距离或切比雪夫距离),或者调整K值以获得更好的性能。
  3. 性能优化:在大数据集上,KNN算法的计算复杂度较高。通过自己实现该算法,你可以对算法进行优化,例如使用KD树来加速搜索邻居。
  4. 无依赖:自己实现KNN算法可以让你更好地了解算法的内部工作原理,无需依赖外部库。

想更深入地了解KNN算法的工作原理,或者需要对算法进行定制和优化,自己实现KNN算法是有意义的。只是想快速应用到项目上,那么使用sklearn是更好的选择。

9.3、案例

二手车预测案例【回归问题】

import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
#读取数据
df = pd.read_csv('data.csv')#清洗数据
# 把颜色独热编码
df_colors = df['Color'].str.get_dummies().add_prefix('Color: ')
# 把类型独热编码
df_type = df['Type'].apply(str).str.get_dummies().add_prefix('Type: ')
# 添加独热编码数据列
df = pd.concat([df, df_colors, df_type], axis=1)
# 去除独热编码对应的原始列
df = df.drop(['Brand', 'Type', 'Color'], axis=1)
# 数据转换
matrix = df.corr()
f, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(matrix, square=True)
plt.title('Car Price Variables')from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.preprocessing import StandardScaler
import numpy as npX = df[['Construction Year', 'Days Until MOT', 'Odometer']]
y = df['Ask Price'].values.reshape(-1, 1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=41)X_normalizer = StandardScaler() # N(0,1) 
X_train = X_normalizer.fit_transform(X_train)
X_test = X_normalizer.transform(X_test)y_normalizer = StandardScaler()
y_train = y_normalizer.fit_transform(y_train)
y_test = y_normalizer.transform(y_test)knn = KNeighborsRegressor(n_neighbors=2)
knn.fit(X_train, y_train.ravel())#Now we can predict prices:
y_pred = knn.predict(X_test)
y_pred_inv = y_normalizer.inverse_transform(y_pred)
y_test_inv = y_normalizer.inverse_transform(y_test)# Build a plot
plt.scatter(y_pred_inv, y_test_inv)
plt.xlabel('Prediction')
plt.ylabel('Real value')# Now add the perfect prediction line
diagonal = np.linspace(500, 1500, 100)
plt.plot(diagonal, diagonal, '-r')
plt.xlabel('Predicted ask price')
plt.ylabel('Ask price')
plt.show()print(y_pred_inv)
  • StandardScaler(),特征缩放函数
  • fit_transform(),根据给定数据集的特点来调整模型的参数,同时可以对数据进行转换
  • inverse_transform(),在scikit-learn中,转换回原始数据并不是通过计算数据中的协方差矩阵和特征向量来实现的

KNN如何解决回归问题的?

KNN用于回归问题时,模型从训练数据集中选择离该数据点最近的k个数据点,并且把这些数据的y值取均值,把求出的这个均值作为新数据点的预测值。【对应:分类中投票高者做结果】


http://www.ppmy.cn/news/104795.html

相关文章

使用KubeSphere3.3在Ubuntu20.04的Kubernetes1.24上部署Word Press

使用KubeSphere3.3在Ubuntu20.04的Kubernetes1.24上部署Word Press 前言 之前已经部署了KubeSphere和K8S的基础环境:https://lizhiyong.blog.csdn.net/article/details/126236516 部署了大数据统一文件编排层Alluxio:https://lizhiyong.blog.csdn.net…

软考A计划-试题模拟含答案解析-卷十

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 👉关于作者 专注于Android/Unity和各种游戏开发技巧,以及各种资源分享&am…

LinuxC_线程

LinuxC_线程 1. 为什么使用线程2. 什么是线程3. 线程的优点、缺点4. 线程的应用场合5. 线程的使用1. 线程的创建2. 线程的终止3. 等待指定线程结束4. 使用线程程序的编译5. 线程的同步6. 线程条件变量 1. 为什么使用线程 使用fork创建进程以执行新的任务,该方式的代…

SpringBoot——原理(自动配置_案例(自定义阿里云文件上starter))

starter定义 starter就是springboot中的起步依赖,虽然springboot已经提供了很多的起步依赖,但是在实际项目开发中可能会用到和第三方的技术,不是所有第三方在springboot中都有收录。 比如之前文章中有用到过的阿里云OSS,阿里云并…

修改element Plus的主题样式

安装element plus 安装icon pnpm install element-plus pnpm install element-plus/icons-vue main.ts配置 icon的使用https://element-plus.gitee.io/zh-CN/component/icon.html#%E7%BB%93%E5%90%88-el-icon-%E4%BD%BF%E7%94%A8 import { createApp } from vue import ./sty…

《深入理解计算机系统(CSAPP)》第6章 存储器层次结构 - 学习笔记

写在前面的话:此系列文章为笔者学习CSAPP时的个人笔记,分享出来与大家学习交流,目录大体与《深入理解计算机系统》书本一致。因是初次预习时写的笔记,在复习回看时发现部分内容存在一些小问题,因时间紧张来不及再次整理…

C++强制类型转换

1. static_cast static_cast 是 C 中的一种显式类型转换运算符。 它可以将一个表达式强制转换为指定的类型,并且是静态类型转换,因此不会执行任何运行时类型检查。如果类型转换不合法,则程序可能出现未定义的行为。因此,使用 stat…

计算机组成原理有关缩写

只是帮助记忆,可能原本的全称不是这个,大家注意一下。 英文简写中文含义帮助记忆CPU中央处理器Central Processing UnitPC程序计数器Program CounterIR指令寄存器Instruction RegisterLA锁存器ALatch ALB锁存器BLatch BALU算术逻辑单元Arithmetic Logic…