scikit-learn机器学习(七)--K近邻法

一丶引言

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

猜你喜欢

转载自blog.csdn.net/weixin_38285131/article/details/79866306
今日推荐