一、k-近邻算法概述
1. k-近邻算法的定义
k-近邻算法是一种常用的监督学习算法,用于分类和回归任务。它采用测量不同特征值之间的距离方法进行分类,适用于数值型和标称型数据。其优点是精度高、对异常值不敏感、无数据输入假定;缺点是计算复杂度高、空间复杂度高。
k-近邻算法(kNN)的工作原理:存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最低的分类,作为新数据的分类。
2.k-近邻算法的关键要素
1.距离度量方法
已知数据和测试数据的距离有多种度量方式,比如曼哈顿距离,欧式距离,余弦距离等。在KNN算法中常使用的距离计算方式是欧式距离,以计算两个向量点 A(x1,y1)和B(x2,y2)的距离为例,计算公式如下:
3.KNN算法原理:
当预测一个新样本的类别时,根据它距离最近的 K 个样本点是什么类别来判断该新样本属于哪个类别(多数投票)。
如果k值比较小,相当于我们用较小的领域内的训练样本对实例进行预测。这时,算法的近似误差(Approximate Error)会比较小,因为只有与输入实例相近的训练样本才会对预测结果起作用。但是,它也有明显的缺点:算法的估计误差比较大,预测结果会对近邻点十分敏感,也就是说,如果近邻点是噪声点的话,预测就会出错。因此,k值过小容易导致KNN算法的过拟合。
同理,如果k值选择较大的话,距离较远的训练样本也能够对实例预测结果产生影响。这时候,模型相对比较鲁棒,不会因为个别噪声点对最终预测结果产生影响。但是缺点也十分明显:算法的近邻误差会偏大,距离较远的点(与预测实例不相似)也会同样对预测结果产生影响,使得预测结果产生较大偏差,此时模型容易发生欠拟合。
4.KNN的关键
KNN 算法有两个关键点:1. 点之间距离的计算;2. K 值的选取。
距离计算
样本空间内的两个点之间的距离量度表示两个样本点之间的相似程度:距离越短,表示相似程度越高;反之,相似程度越低。
常用的距离量度方式包括:
闵可夫斯基距离
曼哈顿距离
欧氏距离
切比雪夫距离
余弦距离
其中,常用的距离量度方式是欧氏距离和曼哈顿距离
1.曼哈顿距离
根据闵可夫斯基距离定义,曼哈顿距离的计算公式可以写为:
它测量两点之间的绝对值。
欧氏距离(L2范数)是最易于理解的一种距离计算方法,源自欧氏空间中两点间的距离公式,也是最常用的距离量度。它测量两点之间的直线距离。
通常 KNN 算法中使用的是欧式距离。
二、kNN实现鸢尾花分类
(一)实验过程
1.导入模块
import pandas as pd
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
2.获取数据集
利用sklearn.datasets.load_*从本地获取小规模数据集
#Iris数据集是最常见的分类实验数据集,也被称为鸢尾花卉数据集
# 加载鸢尾花数据集(特征值有4种 目标值有3种)
iris = load_iris()
3.数据集显示及基本处理
对数据集进行数据类型转换,并可视化数据散点图 ;
利用sklearn中train_test_split()函数将数据集拆分为训练集和测试集;
# 数据类型转换,把数据集用DataFrame存储
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
df['target'] = iris.target
# 可视化数据散点图 c表示颜色,不同颜色对应不同的鸢尾花种类
#通过设置font.sans-serif 参数为'SimHei'(黑体),确保在图形中正确显示中文
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure()
plt.scatter(df.iloc[:, 0], df.iloc[:, 1], c=df['target'])
plt.title('鸢尾花数据集显示')
plt.xlabel('花萼长度')
plt.ylabel('花萼宽度')
plt.show()
# 划分训练集和测试集
# x:数据集的特征值,y:数据集的目标值
x_train, x_test, y_train, y_test = train_test_split(df[iris.feature_names], df['target'], test_size=0.2, random_state=25)
4.结果:
4.构造kNN分类器
# 定义kNN分类器,n_neighbors表示选取的最近邻数目(k值最好不超过20)
knn = KNeighborsClassifier( n_neighbors=5 )
5.模型评估
# 模型评估
knn.fit(x_train, y_train)
# 用kNN分类器对测试集进行预测
y_pred = knn.predict(x_test)
# 方法1:比对测试集的预测值和真实值
#print("测试集的预测值:\n", y_pred)
#print("预测值和真实值对比:\n", y_pred==y_test )
# 方法2:直接输出准确率
accuracy = accuracy_score(y_test, y_pred)
print("模型预测的准确率:\n", accuracy)
运行结果如下:
6.探究不同K值对于准确率的影响
# 探究k值影响
model_new = {
KNeighborsClassifier(n_neighbors=2),
KNeighborsClassifier(n_neighbors=3),
KNeighborsClassifier(n_neighbors=4),
KNeighborsClassifier(n_neighbors=5),
KNeighborsClassifier(n_neighbors=6),
KNeighborsClassifier(n_neighbors=7),
KNeighborsClassifier(n_neighbors=8),
KNeighborsClassifier(n_neighbors=9),
KNeighborsClassifier(n_neighbors=10),
}
score_list = [] # 定义一个列表
for model in model_new: # 一一迭代
model.fit(x_train,y_train) # 训练
y_pred = model.predict(x_test)
score = accuracy_score(y_test, y_pred)
score_list.append(score) # 保存准确率
# 不同k值对模型评估准确率影响的柱状图
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.figure()
plt.bar(range(len(score_list)),score_list)
plt.title('不同K值准确率')
plt.show()
三、KNN算法的优势和劣势
优势:
简单好用,容易理解,精度高,理论成熟,既可以用来做分类也可以用来做回归;
可用于数值型数据和离散型数据;
训练时间复杂度为O(n);无数据输入假定;
对异常值不敏感。
劣势:
计算复杂性高;空间复杂性高;
样本不平衡问题(即有些类别的样本数量很多,而其它样本的数量很少);
一般数值很大的时候不用这个,计算量太大。但是单个样本又不能太少,否则容易发生误分。
最大的缺点是无法给出数据的内在含义。