一丶引言
K近邻法是一种分类和回归算法,他输入特征的向量,通过计算新数据与训练数据特征值之间的距离,寻找K个距离最近的邻居进行分类判断,若K=1,则直接分类给他距离最近的数据的那一类。
基本原理是概括为:
给定一个数据集,对于新输入的数据,该数据与数据集中的k个样本最相似,如果这k个样本中的大多数属于某一个类别,则该样本也属于这个类别
特点:
优点:精度高、对异常值不敏感、无数据输入假定,不需要进行训练
缺点:计算复杂度较大,空间复杂度较高,适用于少量样本
K值对结果影响较大
个人理解K近邻法核心:
计算相似度,距离最近则相似度最高
K近邻法在做图像处理时,比如在特征点匹配中,SIFT特征点的描述子是128维,那么怎么判断这两个特征点是同名点,那么就是看这两个点是否相似,就是对两个点的128维特征向量做距离计算,距离最近,则看做相似度最高,则看做同名点
先把最基本的要点写出来,然后再举例子
二丶KNN三要素
1)K值的选择
2)距离的度量
3)分类决策规则
1)K值的选择
当K=1时,这个时候数据直接归类为距离他最近的样本所属的类,此时成为最近邻法
K值的选择会对K近邻法产生重大影响:
1.若K值较小,则相当于较少的样本参与了预测,则其近似误差会减小
优点:只有与实例较近的样本才会起到预测作用
缺点:学习的估计误差会变大,预测结果会对近邻点非常敏感,若近邻点是噪声点,那么预测就会出错,K值过小易发生过拟合问题,
2.若K值较大,则相当于较大邻域内的样本参与了预测
优点:减少学习的估计误差
缺点:学习的近似误差会增大,这时交院的样本也会参与预测作用,对预测的精度会产生较大的影响,假如当K=N(样本数量)时,那么无论输入什么数据,该数据都属于整个样本中数量最多的那一类,k增大,则模型变得简单
最佳k值的选取一般通过交叉验证方法,就是比较使用不同k值的交叉验证平均误差率,选择误差率最小的k值
2)距离的度量
距离的度量主要会用到常见的欧氏距离,曼哈顿距离,距离的远近相当于两个特征向量的相似程度,k近邻法一般采用欧式距离,欧式距离公式:也就是平方和开根号
曼哈顿距离公式:也就是绝对值的和
两个n维向量a(x11,x12,…,x1n)与 b(x21,x22,…,x2n)间的曼哈顿距离
一般情况下,采用欧式距离作为距离度量,但是只适用于连续的变量,在文本分类这种非连续的情况下,汉明距离可以用来作为度量
3)分类决策规则
k近邻法一般采用多数表决,也可以基于距离进行加权投票,距离越近权重越大。
三丶例子
模拟了一组数据
每个样本具有三个特征,并给出了量化之后的特征值和所属类型,对于输入的实例,判断其所属类型?
1)创建数据
def create_data():
data={
'N1':[12,76,7,'A'],
'N2':[56,12,9,'C'],
'N3':[12,2,86,'B'],
'N4':[7,12,53,'B'],
'N5':[69,11,3,'C'],
'N6':[16,82,2,'A'],
'N7':[11,42,7,'A'],
'N8':[13,9,78,'B'],
'N9':[73,19,12,'C'],
'N10':[2,3,45,'B'],
'N11':[82,14,6,'C'],
'N12':[14,86,2,'A']
}
return data
2)计算输入实例的距离
def compute_distance(datasets,data):
knn=[]
for key,v in datasets.items():
distance=np.sqrt((data[0]-v[0])**2+(data[1]-v[1])**2+(data[2]-v[2])**2)
knn.append([key,round(distance,2)])
for i in knn:
print(i)
return knn
结果:
3)按相似度由高到低进行排序
knn=compute_distance(datasets,data)#返回knn列表
knn.sort(key=lambda dis:dis[1])#对字典根据键值(也就是相似度)进行排序
for i in knn:#将排好序的进行输出
print(i)
结果:
根据结果我们可以看到排在前四位的是N7,N1,N6,N12
4)确定所属类别 取K=5
def print_catagory(K,knn):#K为最近邻样本个数
knn=knn[:K]#取前几个最近的
print(knn)
catagory_dict={}
for each in knn:
catagory=datasets[each[0]][3]#最近的样本所属的类别
print(catagory)
#统计最近邻的几个样本所属类别
if catagory in catagory_dict:#若样本类别在字典中则次数+1
catagory_dict[catagory]+=1
else:
catagory_dict[catagory]=1#若不在,次数设置为1
print(catagory_dict)
print_catagory(5,knn)
输出结果:
可知,最近的五个样本中,四个属于A类别,则输入实例属于A类别,这就是K最近邻法进行分类的原理
四丶scikit-learn机器学习库实现K近邻
1)KNN分类
利用scikit-learn自带的手写识别数据集进行训练和测试
from sklearn import neighbors,datasets
from sklearn.model_selection import train_test_split
def load_classification_data():
digits=datasets.load_digits()
x_train=digits.data
y_train=digits.target
return train_test_split(x_train,y_train,test_size=0.25,random_state=0,stratify=y_train)
def test_KneighborsClassifier(*data):
x_train,x_test,y_train,y_test=data
clf=neighbors.KNeighborsClassifier()
clf.fit(x_train,y_train)
print("Train score:%f"%clf.score(x_train,y_train))
print("Test score:%f"%clf.score(x_test,y_test))
x_train,x_test,y_train,y_test=load_classification_data()
test_KneighborsClassifier(x_train,x_test,y_train,y_test)
结果显示如下:
Train score:0.991091
Test score:0.980000
KNeigborClassifier()可选择参数对结果的影响:
1.weight
- ‘uniform’:所有近邻节点的权重都一样
- ‘distance’:邻居节点的投票权重于距离成反比,节点越近,投票权重越大
2.algorithm
- ‘ball_tree’:球树算法
- ‘kd_tree’: kd树搜索算法
- ‘brute’:暴力搜索算法
- ‘auto’:自动选择合适的算法**
关于k-d树和暴力匹配我的另外两篇博客有提到:
K-D树数据结构介绍及C++实现
图像拼接之特征点匹配–距离筛选,余弦角筛选,相似度和ransac筛选
3.p值
- p=1:曼哈顿距离
- p=2:欧氏距离
4.n_neigbors:一个整数,指定k值
看一下权重对精度影响
def test_KneighborsClassifier(*data):
wight_list=['uniform','distance']
x_train,x_test,y_train,y_test=data
for weight in wight_list:
clf=neighbors.KNeighborsClassifier(weights=weight)#选择不同的权重
clf.fit(x_train,y_train)
print("weight:%s........."%weight)
print("Train score:%f"%clf.score(x_train,y_train))
print("Test score:%f"%clf.score(x_test,y_test))
输出结果为:
weight:uniform.........#uniform 权重相同
Train score:0.991091
Test score:0.980000
weight:distance.........#反距离权重 distance
Train score:1.000000
Test score:0.980000
看一下k值对精度的影响
clf=neighbors.KNeighborsClassifier(n_neighbors=10,weights=weight) #n_neighbor默认是为5,这里改成10
结果:
weight:uniform.........
Train score:0.987379
Test score:0.975556
weight:distance.........
Train score:1.000000
Test score:0.977778
随着k值的增多,精度有所下降,对于权重uniform和distance随着k值的增大 uniform精度下降很快,distance影响不大,因为随着距离变远,权重越来越小,影响几乎为0,所以k值较大时,最好选择反距离加权
参考:
《python大战机器学习》
https://blog.csdn.net/saltriver/article/details/52502253