1 K-近邻算法(KNN)概念
K Nearest Neighbor算法又叫KNN算法,这个算法是机器学习里面一个比较经典的算法, 总体来说KNN算法是相对比较容易理解的算法
1.1定义
如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
来源:KNN算法最早是由Cover和Hart提出的一种分类算法
1.2距离公式
- 欧式距离(Euclidean Distance):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IChgQdJo-1637130478321)(D:\BaiduNetdiskDownload\资料-边学边练超系统掌握人工智能机器学习算法\机器学习讲义\机器学习讲义\机器学习(算法篇)\K-近邻算法\images\1.3 欧式距离1.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ceLlyDZM-1637130478323)(D:\BaiduNetdiskDownload\资料-边学边练超系统掌握人工智能机器学习算法\机器学习讲义\机器学习讲义\机器学习(算法篇)\K-近邻算法\images\1.4 欧式距离2.png)]
- 曼哈顿距离(Manhattan Distance):
在曼哈顿街区要从一个十字路口开车到另一个十字路口,驾驶距离显然不是两点间的直线距离。这个实际驾驶距离就是“曼哈顿距离”。曼哈顿距离也称为“城市街区距离”(City Block distance)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7QnbcCdP-1637130478325)(D:\BaiduNetdiskDownload\资料-边学边练超系统掌握人工智能机器学习算法\机器学习讲义\机器学习讲义\机器学习(算法篇)\K-近邻算法\images\1.5 曼哈顿距离.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wHFxjZ3t-1637130478328)(D:\BaiduNetdiskDownload\资料-边学边练超系统掌握人工智能机器学习算法\机器学习讲义\机器学习讲义\机器学习(算法篇)\K-近邻算法\images\1.6 曼哈顿距离.png)]
1.3 K值的选择
100 0.3
50 0.88
20 0.98
10 1
5 1
1 0.94
- K值过小
- 选择较小的K值,“学习”近似误差会减小,只有与输入实例较近或相似的训练实例才会对预测结果起作用,与此同时带来的问题是“学习”的估计误差会增大,换句话说,K值的减小就意味着整体模型变得复杂,容易发生过拟合,对现有的训练集能有很好的预测,但是对未知的测试样本将会出现较大偏差的预测。
- k值过大:
- 选择较大的K值,其优点是可以减少学习的估计误差,但缺点是学习的近似误差会增大,容易受到样本均衡的影响。这时候,与输入实例较远(不相似的)训练实例也会对预测器作用,使预测发生错误,且K值的增大就意味着整体的模型变得简单,容易发生欠拟合。
1.5 kd树
-
实现k近邻算法时,**主要考虑的问题是如何对训练数据进行快速k近邻搜索。****k近邻法最简单的实现是线性扫描(穷举搜索),即要计算输入实例与每一个训练实例的距离。计算并存储好以后,再查找K近邻。**当训练集很大时,计算非常耗时。为了提高kNN搜索的效率,可以考虑使用特殊的结构存储训练数据,以减小计算距离的次数。
-
kd树(K-dimension tree)是**一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。**kd树是一种二叉树,表示对k维空间的一个划分,构造kd树相当于不断地用垂直于坐标轴的超平面将K维空间切分,构成一系列的K维超矩形区域。kd树的每个结点对应于一个k维超矩形区域。利用kd树可以省去对大部分数据点的搜索,从而减少搜索的计算量。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C5VsEbjA-1637130478329)(D:\BaiduNetdiskDownload\资料-边学边练超系统掌握人工智能机器学习算法\机器学习讲义\机器学习讲义\机器学习(算法篇)\K-近邻算法\images\kd树4.png)]
- 树的建立
给定一个二维空间数据集:T={(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},构造一个平衡kd树。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DyPz0QrJ-1637130478330)(D:\BaiduNetdiskDownload\资料-边学边练超系统掌握人工智能机器学习算法\机器学习讲义\机器学习讲义\机器学习(算法篇)\K-近邻算法\images\kd树6.png)]
- 查找
假设标记为星星的点是 test point, 绿色的点是找到的近似点,在回溯过程中,需要用到一个队列,存储需要回溯的点,在判断其他子节点空间中是否有可能有距离查询点更近的数据点时,做法是以查询点为圆心,以当前的最近距离为半径画圆,这个圆称为候选超球(candidate hypersphere),如果圆与回溯点的轴相交,则需要将轴另一边的节点都放到回溯队列里面来。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VLSjYcC8-1637130478331)(D:\BaiduNetdiskDownload\资料-边学边练超系统掌握人工智能机器学习算法\机器学习讲义\机器学习讲义\机器学习(算法篇)\K-近邻算法\images\kd树7.png)]
1.6 标准化
通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内
- 公式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FAR6OP9z-1637130478332)(D:\BaiduNetdiskDownload\资料-边学边练超系统掌握人工智能机器学习算法\机器学习讲义\机器学习讲义\机器学习(算法篇)\K-近邻算法\images\标准化公式.png)]
作用于每一列,mean为平均值,σ为标准差
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pq02KUVi-1637130478334)(C:\Users\HP\Desktop\2.png)]
- 对于标准化来说:如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改变较小。
2. 数据处理
2.1导入数据集并生成表格
from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
iris = load_iris()
iris_d = pd.DataFrame(data=iris.data, columns=['Sepal_Length', 'Sepal_Width', 'Petal_Length', 'Petal_Width'])
iris_d["target"] = iris.target
print(iris_d)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XTqEg9fu-1637130478335)(C:\Users\HP\Desktop\1.png)]
2.2鸢尾花特征值分布图
def iris_plot(data, col1, col2):
sns.lmplot(x=col1, y=col2, data=data, hue="target", fit_reg=True)
plt.title("鸢尾花数据显示")
plt.figure(figsize=(20,8),dpi=100)
plt.show()
iris_plot(iris_d, 'Sepal_Length', 'Petal_Width')
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HeacsI76-1637130478337)(C:\Users\HP\Desktop\2.png)]
2.3数据集的划分
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=1/3, random_state=42)
2.4 进行数据预处理(特征值和目标值标准化)
from sklearn.preprocessing import StandardScaler
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.fit_transform(x_test)
3. 预测结果
3.1 不进行数据预处理
knn0 = KNeighborsClassifier( n_neighbors=5, weights='uniform', algorithm='brute', leaf_size=15, p=1, metric='minkowski', metric_params=None, n_jobs=1)
print(time.time())
knn0.fit(x_train, y_train)
print(time.time())
print("预测结果是是:\n",knn0.predict(x_test))
print("对比真实值和预测值:\n",knn0.predict(x_test) == y_test)
score = knn0.score(x_test,y_test)
print("准确率为:\n",score)
1605928729.8472779
1605928729.8508410
预测结果是是:
[1 0 2 1 1 0 1 2 1 1 2 0 0 0 0 1 2 1 1 2 0 2 0 2 2 2 2 2 0 0 0 0 1 0 0 2 1
0 0 0 2 1 1 0 0 1 1 2 1 2]
对比真实值和预测值:
[ True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True False True
True True]
准确率为:
0.98
3.2 使用暴力搜索和曼哈顿距离(Manhattan Distance)
knn = KNeighborsClassifier( n_neighbors=5, weights='uniform', algorithm='brute', leaf_size=15, p=1, metric='minkowski', metric_params=None, n_jobs=1)
print(time.time())
knn.fit(x_train, y_train)
print(time.time())
print("预测结果是是:\n",knn.predict(x_test))
print("对比真实值和预测值:\n",knn.predict(x_test) == y_test)
score = knn.score(x_test,y_test)
print("准确率为:\n",score)
1605928492.4287689
1605928492.4318516
预测结果是是:
[1 0 2 1 1 0 1 2 1 1 2 0 0 0 0 1 2 1 1 2 0 2 0 2 2 2 2 2 0 0 0 0 1 0 0 2 1
0 0 0 2 1 1 0 0 1 2 2 1 2]
对比真实值和预测值:
[ True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True]
准确率为:
1.0
3.3 使用kd树和曼哈顿距离(Manhattan Distance)
knn1 = KNeighborsClassifier( n_neighbors=5, weights='uniform', algorithm='kd_tree', leaf_size=15, p=1, metric='minkowski', metric_params=None, n_jobs=1)
print(time.time())
knn1.fit(x_train, y_train)
print(time.time())
print("预测结果是是:\n",knn1.predict(x_test))
print("对比真实值和预测值:\n",knn1.predict(x_test) == y_test)
score = knn1.score(x_test,y_test)
print("准确率为:\n",score)
1605928492.5255845
1605928492.5265813
预测结果是是:
[1 0 2 1 1 0 1 2 1 1 2 0 0 0 0 1 2 1 1 2 0 2 0 2 2 2 2 2 0 0 0 0 1 0 0 2 1
0 0 0 2 1 1 0 0 1 2 2 1 2]
对比真实值和预测值:
[ True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True]
准确率为:
1.0
3.4 使用kd树和欧式距离(Euclidean Distance):
knn2 = KNeighborsClassifier( n_neighbors=5, weights='uniform', algorithm='kd_tree', leaf_size=15, p=2, metric='minkowski', metric_params=None, n_jobs=1)
print(time.time())
knn2.fit(x_train, y_train)
print(time.time())
print("预测结果是:\n",knn2.predict(x_test))
print("对比真实值和预测值:\n",knn2.predict(x_test) == y_test)
score = knn2.score(x_test,y_test)
print("准确率为:\n",score)
1605928549.0947423
1605928549.0957396
预测结果是:
[1 0 2 1 1 0 1 2 1 1 2 0 0 0 0 2 2 1 1 2 0 2 0 2 2 2 2 2 0 0 0 0 1 0 0 2 1
0 0 0 2 1 1 0 0 1 2 2 1 2]
对比真实值和预测值:
[ True True True True True True True True True True True True
True True True False True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True]
准确率为:
0.98
4.结论
时间 准确率
暴力搜索+不处理+曼哈顿距离 0.003563249588012695 0.98
暴力搜索+处理 +曼哈顿距离 0.003082752227783203 1.0
KD树 +处理 +曼哈顿距离 0.000996828079223632 1.0
准确率
暴力搜索+不处理+曼哈顿距离 0.003563249588012695 0.98
暴力搜索+处理 +曼哈顿距离 0.003082752227783203 1.0
KD树 +处理 +曼哈顿距离 0.000996828079223632 1.0
KD树 +处理 +欧式距离 0.000997304916381836 0.98