欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

KNN算法

程序员文章站 2024-03-19 16:25:10
...

K—近邻算法详解

本文目录

1. 首先给出算法定义 
2. 抽象举例解释  
3. 现实举例解释
4. 算法描述
5. 利用UCI中的数据集解释
6. K近邻算法的三个基本要素
7. 总结
8. 问题讨论
9. 代码块 

1、概念定义

   第一句:给定一个带标签的样本数据集合(称为:训练集)
   第二句:当输入没有标签的新数据(新数据:测试集中的数据)后
   第三句:将新数据的每个特征与训练集中所有数据对应的特征进行相似性比较
   第四句:选择训练集中前K个最相似(最近邻)的数据,提取训前K个最相似的数据的分类标签,(说明:通常K是不大于20的整数)。
   第五句:选择这K个最相似数据中出现次数最多的类别标签,作为新数据的类别标签

2、抽象举例解释

例子1:图形判断

    1. 第一句:给定一个带标签的样本数据集合(称为:训练集)
***如下图所示:红色三角形和蓝色正方形组成的集合称为训练集,标签只有三角形,正方形。***
    2. 第二句:当输入没有标签的新数据(新数据:测试集中的数据)后。

图中,中间的绿色图形表示的是没有标签的新数据
KNN算法

   3. 第三句:将新数据的每个特征与训练集中所有数据对应的特征进行相似性比较
   ***这里采用欧式距离进行比较,即:比较两点间的距离的大小。距离越大,相似性就越小;距离越小,相似性就越大。**

遗留问题1:相似性比较方法有哪些?

KNN算法

4.  第四句:选择训练集中前K个最相似(距离最小)的数据,提取训前K个最相似的数据的分类标签, 

遗留问题2:k的值设定多少才合适?

5.  第五句:选择这K个最相似数据中出现次数最多的类别标签,作为新数据的类别标签

遗留问题3:多数表决规则怎样通过数学来解释?

3、现实举例解释

例子2:电影类型评估

  1. 第一句:给定一个带标签的样本数据集合(称为:训练集) 
  2. 第二句:当输入没有标签的新数据(新数据:测试集中的数据)后
  3. 第三句:将新数据的每个特征与训练集中所有数据对应的特征进行相似性比较

由于每个样本只有两个属性,因此采用和例子1相同的方法来比较两个样本间的相似性,即:将该数据映射到二维坐标平面上,比较两点间的距离的大小。
KNN算法

    4. 第四句:选择训练集中前K个最相似(距离最小)的数据,提取训前K个最相似的数据的分类标签,

如果k =3,则分别提取《泰坦尼克号》、《夏洛特烦恼》、《从你的全世界路过》三个数据的电影类型,分别是爱情片、爱情片、爱情片。

 5. 第五句:选择这K个最相似数据中出现次数最多的类别标签,作为新数据的类别标签

KNN算法
未知电影的电影类型为:爱情片

   基于前面两个简单例子,对K近邻概念定义中的每一句话进行了解释。 下面通过前面两个例子给出K近邻算法的正式化描述如下,并对其进行说明。

4、算法描述

   基于前面两个简单例子,对K近邻概念定义中的每一句话进行了解释。 下面通过前面两个例子给出K近邻算法的正式化描述如下,并对其进行说明。

KNN算法

  接下来,将根据该通过一个对UCI上的具体数据集的实验来进一步说明该算法。

6. 利用UCI中的数据集解释

数据集:mushroom数据集

  1. 数据集介绍

     ***蘑菇数据集中包括两类蘑菇,一类是有毒蘑菇,一类是无毒蘑菇。每个蘑菇有22个属性,介绍如下:***
      标签:有毒 = 1,无毒 = 2
      属性1. cap-shape: bell=3, conical=4, convex=5, flat=6 , knobbed=7, sunken=8 
      属性2. cap-surface: fibrous=9, grooves=10, scaly=11, smooth=12  
      属性3.cap-color:brown=13, buff=14, cinnamon=15, gray=16, green=17, pink=18,
                  purple=19, red=20, white=21, yellow=22
      .........
      属性22.
      具体数据如下所示:
      2 6 10 16 23 28 34 36 39 44 53 56 59 63 69 76 85 86 90 93 98 110 116
      1 3 11 16 24 29 34 36 39 42 52 56 61 66 70 77 85 86 90 95 101 110 117
      2 6 10 17 23 28 34 36 39 44 53 56 59 63 69 78 85 86 90 93 99 110 116
      1 3 10 16 24 29 34 36 39 43 52 56 61 66 70 77 85 86 90 95 101 110 117
    
  2. 数据处理

     为了方便计算,在输入数据之前需要对数据进行处理,采用Python语言处理如下:
     属性表示X:
     [[   3.    9.   13. ...,   98.  107.  113.]
      [   3.    9.   14. ...,   99.  108.  114.]
      [   4.    9.   15. ...,   99.  108.  115.]
      ..., 
      [   6.    9.   13. ...,  102.  110.  117.]
      [   7.   10.   17. ...,  102.  110.  119.]
      [   6.    9.   17. ...,  102.  110.  119.]] 
     标签表示Y:
     [1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, ......]
    

    代码如下所示:

    def createDataset(fileName):
        fr = open(fileName)
        read_line = fr.readlines()
        number_line = len(read_line)
        data_Mat = zeros((number_line,22))
        label_Mat = []
        index = 0
        for line in read_line:
            line = line.strip()
            splitLine = line.split( )
            data_Mat[index,:]=splitLine[1:]
            label_Mat.append(int(splitLine[0]))
            index +=1
        return data_Mat , label_Mat

3 实现过程

**输入1:训练数据集**
    T= {(x1,y1),(x2,y2),(x3,y3),(x4,y4),......(xN,yN)
      其中,xi为实例的特征向量,yi为实例的类别,i=1,2...N。
    例如:
      x1 = (6 10 16 23 28 34 36 39 44 53 56 59 63 69 76 85 86 90 93 98 110 116)
      y1= 2
      经过处理后输入的是:T={(X,Y)}
      本次实验使用了4858个数据作为训练集,正反例比为1:1。

**输入2:测试集**
    测试集由2000个数据组成,正反例比为1:1。

**输出:测试集中每个实例x所属的类y**
      1、根据给定的距离度量,在训练集T中找出与测试数据x最邻近的K个点,涵盖这个K个点的x的领域记作Nk(x)
          距离度量:欧式距离
          K值选取:k = 6
      2、在Nk(x)中根据分类决策规则(如:多数表决)决定x的类别y

算法代码如下:

def classify(inX , dataSet , labels ,k):
dataSetsize = len(dataSet)
diffMat = tile(inX, (dataSetsize,1))
diffMat1 = diffMat-dataSet
sqDiffMat = diffMat1**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
print(distances)
sortedDistIndicies = distances.argsort()
classCount = {}
for i in range(k):
    voteIlabel = labels[sortedDistIndicies[i]]
    classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse = True)
return sortedClassCount[0][0]

7、K-近邻的三要素

讲解 ‘1.1抽象举例解释’ 时遗留的三个问题:

1:相似性比较方法有哪些?
2:k的值设定多少才合适?
3:多数表决规则怎样通过数学来解释?

分别对应着K近邻模型的三个基本要素:

1.距离度量(即:相似度度量)
2.K值得选择
3.分类决策规则

接下来分别对这三个基本要素进行解释说明:
7.1 距离度量

   K近邻模型的特征空间一般是n维实数向量空间,使用的距离可以使欧式距离,也是可以是其它距离(曼哈顿距离、 切比雪夫距离......等)

欧氏距离

   最常见的两点之间或多点之间的距离表示法,又称之为欧几里得度量,它定义于欧几里得空间中,如点 x = (x1,...,xn) 和 y = (y1,...,yn) 之间的距离为:

KNN算法

曼哈顿距离

   通俗来讲,想象你在曼哈顿要从一个十字路口开车到另外一个十字路口,驾驶距离是两点间的直线距离吗?显然不是,除非你能穿越大楼。而实际驾驶距离就是这个“曼哈顿距离”,此即曼哈顿距离名称的来源, 同时,曼哈顿距离也称为城市街区距离(City Block distance)。

KNN算法

本次实验分别采用了欧式距离和曼哈顿距离来进行,下面给出采用两种不同距离对样本正确率所产生的影响。

曼哈顿距离和欧式距离对比分析

KNN算法

分析:

1、当K=1或2时, 使用曼哈顿距离和欧式距离对测试数据的正确率的影响是相同的。
2、从整体数据的准确率来看,使用曼哈顿距离比使用欧式距离得到的数据准确率要高。
3、从K的特殊取值来看,当K= 4时,使用欧式距离得到的准确率要比使用曼哈顿得到的准确率高。

结论:

  不同的距离度量方法产生的效果不同,通常情况下采用欧式距离来计算。

7.2 K值选择

K值的选择会对K近邻法的结果产生重大影响。
   如果选择较小的K值,就相当于用较小的邻域中的训练实例进行预测,只有与输入实例较近的训练实  例才会对预测结果起作用,但缺点是预测结果会对邻近的实例点非常敏感。如果邻近的实例点恰好是噪声,预测就会出错。
   如果选择较大的K值,与输入实例较远的训练实例也会对预测结果起作用,此时,误差将会增大。
如果K = N。那么无论输入实例是什么,都将预测它属于在训练实例中最多的类。

总结: 基于前人经验,在一般情况下,K的取值在1到20之间。

不同K值范围的准确率

   为了验证前人经验的准确性,此次实验分别画出了K从1到20和K从1到50区间内不同取值时的准确率。如下图所示:

KNN算法
KNN算法

分析:

 1.对比两幅图,当K=4时,使用K近邻对测试数据的实验的准确率最高,效果最好。
 2.从右图中可以看到,1到25区间内,准确率呈整体下降趋势,在30左右时,虽然有所回升,但是整体还是呈下降趋势。

总结:前人经验是可信的。K值一般可以取1到20之间的整数。

7.3 分类决策

KNN算法

8 总结

 1、本次汇报首先给出K近邻算法的定义,然后通过抽象化和现实中电影类型2个例子对定义中的每一句话进行了解释。
 2、然后给出了K近邻算法的正式算法描述,使用UCI上的蘑菇数据集进行了大量实验。画出了使用曼哈顿距离和欧式距离所产生的不同准确率的散点图,画出了K的不同取值范围的准确率的散点图。
 3、根据对散点图的分析,得出了一些关于距离度量和K值选择的结论,最后解释了分类决策中多数表决规则。至此,K近邻算法的三个基本要素已经逐一解释完毕。

9 问题讨论

 1、距离度量方法是否可以使用其他度量方法,性能如何?哪一种性能最佳?
 2、是否存在某种方法来准确的选择K的取值,从而使算法性能达到最佳状态?

10 代码块

数据处理:

from numpy import *

def createDataset(fileName):
    fr = open(fileName)
    read_line = fr.readlines()
    number_line = len(read_line)
    data_Mat = zeros((number_line,22))
    label_Mat = []
    index = 0
    for line in read_line:
        line = line.strip()
        splitLine = line.split( )
        data_Mat[index,:]=splitLine[1:]
        label_Mat.append(int(splitLine[0]))
        index +=1
    return data_Mat , label_Mat

data_Mat, label_Mat = createDataset('Test_Data.dat')
n=0
for i in range(0,len(label_Mat)):
    if label_Mat[i] == 1:
        n+=1
print(n)
print(data_Mat)
print(label_Mat)

KNN算法:

from numpy import *
import operator
from A1_dataSet import createDataset

def classify(inX , dataSet , labels ,k):
    dataSetsize = len(dataSet)
    diffMat = tile(inX, (dataSetsize,1))
    diffMat1 = diffMat-dataSet
    sqDiffMat = diffMat1**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    print(distances)
    sortedDistIndicies = distances.argsort()
    classCount = {}
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
        sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse = True)
    return sortedClassCount[0][0]


data_Mat, label_Mat = createDataset('Train_Data.dat')
inX = [6,9,13,24,32,34,36,38,48,53,58,61,66,67,77,85,86,90,94,102,110,119]
Class= classify(inX ,data_Mat, label_Mat,100)
print(Class)

计算错误率:

from numpy import *
from A1_dataSet import createDataset
from A2_KNN import classify

def countError(Test_data,Test_label, Train_data,Train_label,k):
    Error = 0
    index = 0
    pred_Mat = []
    for data in Test_data:
        pred_label = classify(data, Train_data,Train_label,k)
        pred_Mat.append(pred_label)
        if pred_label != Test_label[index]:
            Error+=1
        index+=1
    Right_Rat = 1-Error /len(Test_label)
    return Error,Right_Rat
'''
Train_data, Train_label =createDataset('chess_TrainData.dt')
Test_data,Test_label = createDataset('chess_TestData.dt')
Error,ErrorRat = countError(Test_data,Test_label, Train_data,Train_label,4)
print(Error)
print(ErrorRat)
'''

不同K取值:

from numpy import *
from A1_dataSet import createDataset
from A3_countError import countError

def dif_K(k):
    Train_data, Train_label = createDataset('chess_TrainData.dt')
    Test_data, Test_label = createDataset('chess_TestData.dt')
    num_right = zeros((k,3))
    best_K = 0
    for i in range(1,k+1):
        Error, Right_Rat=countError(Test_data, Test_label, Train_data, Train_label, i)
        num_right[i-1,0] = i
        num_right[i-1,1] = Error
        num_right[i-1,2] = Right_Rat
        if best_K < Right_Rat:
            best_K=Right_Rat
    return num_right,best_K

num_right,best_K = dif_K(20)
print(num_right)
print(best_K)

不同距离度量方式比较:

from numpy import *
import matplotlib
import matplotlib.pyplot as plt

Mhd = array([[1,0.8289638],
       [2,0.8289638 ],
       [3,0.82397004],
       [4,0.82771536],
       [5,0.82022472],
       [6,0.82646692],
       [7,0.80898876],
       [8,0.8164794],
       [9,0.80024969],
       [10,0.81523096],
       [11,0.80024969],
       [12,0.80898876],
       [13,0.79775281],
       [14,0.80649189],
       [15,0.79026217],
       [16,0.80024969],
       [17,0.78651685],
       [18,0.78526841],
       [19,0.78027466],
       [20,0.79650437]])
Os = array([[1,0.8289638 ],
      [2,0.8289638 ],
      [3,0.82022472],
      [4,0.83645443],
      [5,0.82397004],
      [6,0.82397004],
      [7,0.80649189],
      [8,0.81398252],
      [9,0.79400749],
      [10,0.80524345],
      [11,0.78401998],
      [12,0.79275905],
      [13,0.79026217],
      [14,0.80024969],
      [15,0.79275905],
      [16,0.78776529],
      [17,0.77777778],
      [18,0.78526841],
      [19,0.77652934],
      [20,0.78401998]])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_title("Manhattan and Euclidean")
plt.xlabel('K')
plt.ylabel('Accuracy')
ax.scatter(Mhd[:,0],Mhd[:,1])

ax.scatter(Os[:,0],Os[:,1])
plt.legend('ME')
plt.show()

以上内容仅供参考,如有错误之处,请大家批评指正。