KNN及其改进算法的python实现

一、 马氏距离

我们熟悉的欧氏距离虽然很有用,但也有明显的缺点。它将样品的不同属性(即各指标或各变量)之间的差别等同看待,这一点有时不能满足实际要求。例如,在教育研究中,经常遇到对人的分析和判别,个体的不同属性对于区分个体有着不同的重要性。因此,有时需要采用不同的距离函数。
  如果用dij表示第i个样品和第j个样品之间的距离,那么对一切i,j和k,dij应该满足如下四个条件:
    ①当且仅当i=j时,dij=0
  ②dij>0
  ③dij=dji(对称性)
  ④dij≤dik+dkj(三角不等式)
显然,欧氏距离满足以上四个条件。满足以上条件的函数有多种,本节将要用到的马氏距离也是其中的一种。
  第i个样品与第j个样品的马氏距离dij用下式计算:
    dij =(x i 一x j)‘S-1(x i一xj)
  其中,x i 和x j分别为第i个和第j个样品的m个指标所组成的向量,S为样本协方差矩阵。
  马氏距离有很多优点。它不受量纲的影响,两点之间的马氏距离与原始数据的测量单位无关;由标准化数据和中心化数据(即原始数据与均值之差)计算出的二点之间的马氏距离相同。马氏距离还可以排除变量之间的相关性的干扰。它的缺点是夸大了变化微小的变量的作用。举例说明:

两个样本:
His1 = {3,4,5,6}
His2 = {2,2,8,4}
它们的均值为:
U = {2.5, 3, 6.5, 5}
协方差矩阵为:
S =
| 0.25  0.50  -0.75  0.50  |
| 0.50  1.00  -1.50  1.00  | 
|-0.75  -1.50    2.25  -1.50  |
| 0.50  1.00  -1.50  1.00  |
其中S(i,j)={[His1(i)-u(i)]*[His1(j)-u(j)]+[His2(i)-u(i)]*[His2(j)-u(j)]}/2
下一步就是求出逆矩阵S^(-1)
马氏距离 D=sqrt{[His1-His2] * S^(-1) * [(His1-His2)的转置列向量]}
1)马氏距离的计算是建立在总体样本的基础上的,这一点可以从上述协方差矩阵的解释中可以得出,也就是说,如果拿同样的两个样本,放入两个不同的总体中,最后计算得出的两个样本间的马氏距离通常是不相同的,除非这两个总体的协方差矩阵碰巧相同;
2)在计算马氏距离过程中,要求总体样本数大于样本的维数,否则得到的总体样本协方差矩阵逆矩阵不存在,这种情况下,用欧式距离来代替马氏距离,也可以理解为,如果样本数小于样本的维数,这种情况下求其中两个样本的距离,采用欧式距离计算即可。
3)还有一种情况,满足了条件总体样本数大于样本的维数,但是协方差矩阵的逆矩阵仍然不存在,比如A(3,4),B(5,6);C(7,8),这种情况是因为这三个样本在其所处的二维空间平面内共线(如果是大于二维的话,比较复杂)。这种情况下,也采用欧式距离计算。
4)在实际应用中“总体样本数大于样本的维数”这个条件是很容易满足的,而所有样本点出现3)中所描述的情况是很少出现的,所以在绝大多数情况下,马氏距离是可以顺利计算的,但是马氏距离的计算是不稳定的,不稳定的来源是协方差矩阵,这也是马氏距离与欧式距离的最大差异之处。
综上,我们用python编写了马氏距离,如下:

distances=[]
for i in range(dataSetSize):
    x = numpy.array(dataSet)
    xt=x.T
    D=numpy.cov(xt)
    invD=numpy.linalg.inv(D)
    tp=inX-dataSet[i]
    distances.append(numpy.sqrt(dot(dot(tp,invD),tp.T)))

最后得到的distances就是测试样本和每个训练样本的马氏距离。

二、 wk_NNC算法

wk-NNC算法是对经典knn算法的改进,这种方法是对k个近邻的样本按照他们距离待分类样本的远近给一个权值w:

是第i个近邻的权值,其中1<i<k,是待测样本距离第i个近邻的距离。

用python实现这个算法比较简单:

def wk_knn(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize,1)) - dataSet

sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1) 
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()        
    classCount={}   
    w=[]     
    for i in range(k):
        w.append((distances[sortedDistIndicies[k-1]]-distances[sortedDistIndicies[i]]\
        )/(distances[sortedDistIndicies[k-1]]-distances[sortedDistIndicies[0]]))
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + w[i]
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

三、 knnm算法

knnm算法运用了训练样本中的每一个模式,对训练样本的每个类

1 ≤ i ≤ c,在每一个类中找出距离测试样本距离最近的k个近邻,假设这k个近邻的均值为,同样的,i从1到c变化,我们得到,如果是M当中距离测试样本最近的,则测试样本属于类。

如下图所示,对于一个两类的问题,每个类选三个近邻,类用*表示,类用o表示,“Y”是测试样本,则Y属于类。

用python实现如下:

def knnm(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet   #tile repeat inX to (dataSetSize,1)
    sqDiffMat = diffMat ** 2
    sqDistances = sqDiffMat.sum(axis=1)  #sum per row
    distances = sqDistances ** 0.5
    sortedDistIndicies = distances.argsort()
    classCount={}
    classNum={}
    i=0
    while i<dataSetSize:
        voteIlabel = labels[sortedDistIndicies[i]]
        if sum(classNum)==10*k:
            break
        elif
classNum.get(voteIlabel,0)==k:
            i += 1
        else:
            classCount[voteIlabel] = classCount.get(voteIlabel,0) \
                                     + distances[sortedDistIndicies[i]]
            classNum[voteIlabel]=classNum.get(voteIlabel,0)+1
            i += 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1))
    return sortedClassCount[0][0]

四、 实验过程

我在手写字符和约会数集分别作了实验,结果如下(k=7):


约会数集错误率


KNN


WK_KNN


KNNM


马氏距离


6%


6.6%


6.2%


欧氏距离


5.8%


6.2%


6.2%

由于手写字符训练样本协方差矩阵不可逆,因此只能求欧氏距离


手写字符错误率


KNN


WK_KNN


KNNM


欧式距离


1.1628%(k=3最小)


0.9514%(k=5最小)


1.2685%(k=3最小)

五、实验小结

欧式距离比马氏距离计算量小得多,速度快,而且可以看出分类的效果甚至比马氏距离要好,,可以看到,在约会数集中,knn的表现要优于其他两种算法,欧式距离的knn错误率最低,而wk_knn在手写字符识别中有较为出色的表现,相对于其他两种算法,knnm并没有想象中的效果。

时间: 2024-11-07 04:44:01

KNN及其改进算法的python实现的相关文章

数据回归分类预测的基本算法及python实现

数据回归分类预测的基本算法及python实现 关于数据的回归和分类以及分析预测.讨论分析几种比较基础的算法,也可以算作是比较简单的机器学习算法. 一.        KNN算法 邻近算法,可以用来做回归分析也可以用来做分类分析.主要思想是采取K个最为邻近的自变量来求取其应变量的平均值,从而做一个回归或者是分类.一般来说,K取值越大,output的var会更小,但bias相应会变大.反之,则可能会造成过拟合.因此,合理的选取K的值是KNN算法当中一个很重要的步骤. Advantages First

分类算法——k最近邻算法(Python实现)(文末附工程源代码)

kNN算法原理 k最近邻(k-Nearest Neighbor)算法是比较简单的机器学习算法.它采用测量不同特征值之间的距离方法进行分类,思想很简单:如果一个样本在特征空间中的k个最近邻(最相似)的样本中大多数属于某一个类别,则该样本也属于这个类别. kNN算法的步骤 第一阶段:确定k值(指最近的邻居的个数),一般是一个奇数 第二阶段:确定距离度量公式.文本分类一般使用夹角余弦,得出待分类数据点和所有已知类别的样本点,从中选择距离最近的k个样本: 第三阶段:统计这k个样本点钟各个类别的数量 kN

机器学习算法与Python实践之(二)支持向量机(SVM)初级

机器学习算法与Python实践之(二)支持向量机(SVM)初级 机器学习算法与Python实践之(二)支持向量机(SVM)初级 [email protected] http://blog.csdn.net/zouxy09 机器学习算法与Python实践这个系列主要是参考<机器学习实战>这本书.因为自己想学习Python,然后也想对一些机器学习算法加深下了解,所以就想通过Python来实现几个比较常用的机器学习算法.恰好遇见这本同样定位的书籍,所以就参考这本书的过程来学习了. 在这一节我们主要是

机器学习算法与Python实践之(七)逻辑回归(Logistic Regression)

机器学习算法与Python实践这个系列主要是参考<机器学习实战>这本书.因为自己想学习Python,然后也想对一些机器学习算法加深下了解,所以就想通过Python来实现几个比较常用的机器学习算法.恰好遇见这本同样定位的书籍,所以就参考这本书的过程来学习了. 这节学习的是逻辑回归(Logistic Regression),也算进入了比较正统的机器学习算法.啥叫正统呢?我概念里面机器学习算法一般是这样一个步骤: 1)对于一个问题,我们用数学语言来描述它,然后建立一个模型,例如回归模型或者分类模型等

常用排序算法的python实现

排序算是编程最基本的算法问题之一了,熟练掌握排序算法也能加深自己对数据结构的理解,也能提高自己的编程能力,以下为个人参考许多大神博客后对常用排序算法的学习总结. 目录: 概述 冒泡排序 直接插入排序 简单选择排序 希尔排序 堆排序 归并排序 快速排序 算法的比较与测试 参考 1. 概述 所谓排序(sorting)就是整理数据的序列,使其按照特定顺序排列的操作.排序在现实生活中(如整理书籍,表格数据等),在计算领域中(如二分查找,图论的最小生成树的Kruskal算法)均有重要意义,所以一种高效的排

k近邻算法的Python实现

k近邻算法的Python实现 0. 写在前面 这篇小教程适合对Python与NumPy有一定了解的朋友阅读,如果在阅读本文的源代码时感到吃力,请及时参照相关的教程或者文档. 1. 算法原理 k近邻算法(k Nearest Neighbor)可以简称为kNN.kNN是一个简单直观的算法,也是机器学习从业者入门首选的算法.先看一个简单的应用场景. 小例子 设有下表,命名为为表1 电影名称 打斗镜头数量 接吻镜头数量 电影类型 foo1 3 104 爱情片 foo2 2 100 爱情片 foo3 1

《机器学习实战》之K-均值聚类算法的python实现

<机器学习实战>之K-均值聚类算法的python实现 最近的项目是关于"基于数据挖掘的电路故障分析",项目基本上都是师兄们在做,我只是在研究关于项目中用到的如下几种算法:二分均值聚类.最近邻分类.基于规则的分类器以及支持向量机.基于项目的保密性(其实也没有什么保密的,但是怕以后老板看到我写的这篇博文,所以,你懂的),这里就不介绍"基于数据挖掘的电路故障分析"的思路了. 废话不多说了,开始正题哈. 基本K-均值聚类算法 基本K均值算法的基本思路为:首先选择

《机器学习实战》之二分K-均值聚类算法的python实现

<机器学习实战>之二分K-均值聚类算法的python实现 上面博文介绍了K-均值聚类算法及其用python实现,上篇博文中的两张截图,我们可以看到,由于K-均值聚类算法中由于初始质心的选取,会造成聚类的局部最优,并不是全局最优,因此,会造成聚类的效果并不理想,为克服K-均值算法收敛于局部最小值的问题,就有了二分K-均值算法. 二分K-均值聚类算法 二分K均值算法是基本K均值算法的直接扩充,其基本思想是:为了得到K个簇,首先将所有点的集合分裂成两个簇,然后从这些簇中选取一个继续分裂,迭代直到产生

读论文《BP改进算法在哮喘症状-证型分类预测中的应用》

总结: 一.研究内容 本文研究了CAL-BP(基于隐层的竞争学习与学习率的自适应的改进BP算法)在症状证型分类预测中的应用. 二.算法思想 1.隐层计算完各节点的误差后,对有最大误差的节点的权值进行正常修正,  而对其它单元的权值都向相反方向修正,用 δ表示隐层节点的权值修正量, 则修正量的调整公式具体为 2.每次算法迭代完以后,计算误差函数的值并与前一次的值进行比较,如果误差函数的值增大,     则代表过调了学习率,应在下一次迭代时以一定比率下调学习率 ],若误差函数的i+1值减小,