KNN分类器

原创 2015年07月07日 10:56:45

KNN学习(K-Nearest Neighbor algorithm,K最邻近方法 )是一种统计分类器,对数据的特征变量的筛选尤其有效。

基本原理

KNN的基本思想是:输入没有标签(标注数据的类别),即没有经过分类的新数据,首先提取新数据的特征并与测试集中的每一个数据特征进行比较;然后从测试集中提取K个最邻近(最相似)的数据特征标签,统计这K个最邻近数据中出现次数最多的分类,将其作为新的数据类别。
KNN的这种基本思想有点类似于生活中的“物以类聚,人以群分”。
在KNN学习中,首先计算待分类数据特征与训练数据特征之间的距离并排序,取出距离最近的K个训练数据特征;然后根据这K个相近训练数据特征所属类别来判定新样本类别:如果它们都属于一类,那么新的样本也属于这个类;否则,对每个候选类别进行评分,按照某种规则确定新的样本的类别。笔者借用下面这个图来做更形象的解释:
这里写图片描述
如上图,图中最小的那个圆圈代表新的待分类数据,三角形和矩形分别代表已知的类型,现在需要判断圆圈属于菱形那一类还是矩形那一类。但是我该以什么样的依据来判断呢?

  1. 看离圆形最近(K=1)的那个类型是什么,由图可知,离圆形最近的是三角形,故将新数据判定为属于三角形这个类别。
  2. 看离圆形最近的3个数据(K=3)的类型是什么,由图可知离圆形最近的三个中间有两个是矩形,一个是三角形,故将新数据判定为属于矩形这个类别。
  3. 看离圆形最近的9个数据(K=9)的类型是什么,由图可知离圆形最近的9个数据中间,有五个是三角形,四个是矩形,故新数据判定为属于三角形这个类别。

上面所说的三种情况也可以说成是1-近邻方法、3-近邻方法、9-近邻方法。。。当然,K还可以取更大的值,当样本足够多,且样本类别的分布足够好的话,那么K值越大,划分的类别就越正确。而KNN中的K表示的就是划分数据时,所取相似样本的个数。
我们都知道,当K=1时,其抗干扰能力就较差,因为假如样本中出现了某种偶然的类别,那么新的数据很有可能被分错。为了增加分类的可靠性,可以考察待测数据的K个最近邻样本 ,统计这K个近邻样本中属于哪一类别的样本最多,就将样本X判属于该类。
当然,如果在样本有限的情况下,KNN算法的误判概率和距离的具体测度方法就有了直接关系。即用何种方式判定哪些数据与新数据近邻。不同的样本选择不同的距离测量函数,这能够提高分类的正确率。通常情况下,KNN可以采用Euclidean(欧几里得)、Manhattan(曼哈顿)、Mahalanobis(马氏距离)等距离用于计算。

  • Euclidean距离为:
    d(x⃗ ,y⃗ )=[i=1n(xiyi)2]
    x⃗ =(x1,x2,...,xn)
    y⃗ =(y1,y2,...,yn)
  • Manhattan距离为:
    d(x⃗ ,y⃗ )=i=1n|xiyi|
  • Mahalanobis距离为:
    d(x⃗ ,y⃗ )=(x⃗ y⃗ )V1(x⃗ y⃗ )
    其中n为特征的维数,Vx⃗ y⃗ 所在的数据集的协方差函数。

下面给出KNN学习的伪代码:

Algorithm  KNN(A[n],k,x)
    Input:
        A[n]为N个训练样本的特征,K为近邻数,x为新的样本;
    Initialize:
        取A[1]~A[k]作为x的初始近邻;
        计算测试样本与x间的欧式距离d(x,A[i]),i=1,2...,k;
        按d(x,A[i])升序排序;
        计算最远样本与x间距离D,即max{d(x,A[i])};
    for(i=k+1;i<=n;i++)
        计算A[i]与x之间的距离d(x,A[i]);
        if (d(x,A[i]))<D  then  用A[i]代替最远样本;
        按照d(x,A[i])升序排序;
        计算最远样本与x间的距离D,即max{d(x,A[i])};
    End for
    计算前K个样本A[i],i=1,2...,k所属类别的概率;
    具有最大概率的类别即为样本x的类;
    Output:x所属的类别。

KNN的不足

1、加入某些类别的样本容量很大,而其他类样本容量很小,即已知的样本数量不均衡,有可能当输入一个和小容量类相同的的新样本时,该样本的K个近邻中,大容量类的样本占多数,从而导致误分类。
针对此种情况可以采用加权的方法,即和该样本距离小的近邻所对应的权值越大,将权值纳入分类的参考依据。
2、分类时需要先计算待分类样本和全体已知样本的距离,才能求得所需的K近邻点,计算量较大,尤其是样本数量较多时。
针对这种情况可以事先对已知样本点进行剪辑,去除对分类作用不大的样本,这一处理步骤仅适用于样本容量较大的情况,如果在原始样本数量较少时采用这种处理,反而会增加误分类的概率。

改进的KNN算法

KNN学习容易受噪声影响,尤其是样本中的孤立点对分类或回归处理有很大的影响。因此通常也对已知样本进行滤波和筛选,去除对分类有干扰的样本。

K值得选取也会影响分类结果,因此需根据每类样本的数目和分散程度选取合理的K值,并且对不同的应用也要考虑K值得选择。

基于组合分类器的KNN改进算法

常用的组合分类器方法有投票法、非投票法、动态法和静态法等,比如简单的投票法中所有的基分类器对分类采取相同的权值;权值投票法中每个基分类器具有相关的动态权重,该权重可以随时间变化。

首先随机选择属性子集,构建多个K近邻分类器;然后对未分类元组进行分类;最后把分类器的分类结果按照投票法进行组合,将得票最多的分类器作为最终组合近邻分类器的输出。

基于核映射的KNN改进算法

将原空间Rn中的样本x映射到一个高维的核空间F中,突出不同类别样本之间的特征差异出,使得样本在核空间中变得线性可分或者近似线性可分,其流程如下所示:
首先进行非线性映射:

Φ:RnF,xΦ(x)
然后在高维的核空间,待分类的样本变为(Φ(x1),...,Φ(xn)),任意两个样本Φ(xi)Φ(xj)之间的距离为:
Φ(xi)Φ(xj)2=K(xi,xi)+K(xj,xj)
其中K(,)为核函数,在此基础上进行KNN分类。

实践代码

下面给出一个简单的KNN分类的MATLAB实践代码:
main.m文件

function main
trainData = [
    0.6213    0.5226    0.9797    0.9568    0.8801    0.8757    0.1730    0.2714    0.2523
    0.7373    0.8939    0.6614    0.0118    0.1991    0.0648    0.2987    0.2844    0.4692
    ];
trainClass = [
    1     1     1     2     2     2     3     3     3
    ];
testData = [
    0.9883    0.5828    0.4235    0.5155    0.3340
    0.4329    0.2259    0.5798    0.7604    0.5298
    ];

% main
testClass = cvKnn(testData, trainData, trainClass);

% plot prototype vectors
classLabel = unique(trainClass);
nClass     = length(classLabel);
plotLabel = {'r*', 'g*', 'b*'};
figure;
for i=1:nClass
    A = trainData(:, trainClass == classLabel(i));
    plot(A(1,:), A(2,:), plotLabel{i});
    hold on;
end

% plot classifiee vectors
plotLabel = {'ro', 'go', 'bo'};
for i=1:nClass
    A = testData(:, testClass == classLabel(i));
    plot(A(1,:), A(2,:), plotLabel{i});
    hold on;
end
legend('1: prototype','2: prototype', '3: prototype', '1: classifiee', '2: classifiee', '3: classifiee', 'Location', 'NorthWest');
title('K nearest neighbor');
hold off;

KNN.m文件

function [Class, Rank] = cvKnn(X, Proto, ProtoClass, K, distFunc)
if ~exist('K', 'var') || isempty(K)
    K = 1;%默认为K = 1
end
if ~exist('distFunc', 'var') || isempty(distFunc)
    distFunc = @cvEucdist;
end
if size(X, 1) ~= size(Proto, 1)
    error('Dimensions of classifiee vectors and prototype vectors do not match.');
end
[D, N] = size(X);

% Calculate euclidean distances between classifiees and prototypes
d = distFunc(X, Proto);

if K == 1, % sort distances only if K>1
    [mini, IndexProto] = min(d, [], 2); % 2 == row%每列的最小元素
    Class = ProtoClass(IndexProto);
    if nargout == 2, % instance indices in similarity descending order
        [sorted, ind] = sort(d'); % PxN
        RankIndex = ProtoClass(ind); %,e.g., [2 1 2 3 1 5 4 1 2]'
        % conv into, e.g., [2 1 3 5 4]'
        for n = 1:N
            [ClassLabel, ind] = unique(RankIndex(:,n),'first');
            [sorted, ind] = sort(ind);
            Rank(:,n) = ClassLabel(ind);
        end
    end
else
    [sorted, IndexProto] = sort(d'); % PxN
    clear d;
    % K closest
    IndexProto = IndexProto(1:K,:);
    KnnClass = ProtoClass(IndexProto);
    % Find all class labels
    ClassLabel = unique(ProtoClass);
    nClass = length(ClassLabel);
    for i = 1:nClass
        ClassCounter(i,:) = sum(KnnClass == ClassLabel(i));
    end
    [maxi, winnerLabelIndex] = max(ClassCounter, [], 1); % 1 == col
    % Future Work: Handle ties somehow
    Class = ClassLabel(winnerLabelIndex);
end

Eucdist.m文件

function d = cvEucdist(X, Y)
 if ~exist('Y', 'var') || isempty(Y)
     %% Y = zeros(size(X, 1), 1);
     U = ones(size(X, 1), 1);
     d = abs(X'.^2*U).'; return;
 end
 V = ~isnan(X); X(~V) = 0; % V = ones(D, N); 
 %clear V;
 U = ~isnan(Y); Y(~U) = 0; % U = ones(D, P); 
 %clear U;
 %d = abs(X'.^2*U - 2*X'*Y + V'*Y.^2);
 d1 = X'.^2*U;
 d3 = V'*Y.^2;
 d2 = X'*Y;
 d = abs(d1-2*d2+d3);

代码效果如下:
这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。转载请注明出处:http://blog.csdn.net/autocyz?viewmode=contents——autocyz 举报

相关文章推荐

平凡而又神奇的贝叶斯方法

概率论只不过是把常识用数学公式表达了出来。 ——拉普拉斯 记得读本科的时候,最喜欢到城里的计算机书店里面去闲逛,一逛就是好几个小时;有一次,在书店看到一本书,名叫贝叶斯方法。当时数学系的课程还没有...

朴素贝叶斯算法matlab实现以及EM算法

这周,继续学习了朴素贝叶斯算法的一部分知识,看了matlab的贝叶斯分类算法。采用草地潮湿原因模型的一个例子来求证贝叶斯概率以及条件概率、联合概率的分析,详见日志http://blog.sina.co...

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

计算机视觉领域顶级期刊、会议及数据库

搜集了一些在计算机视觉领域比较有名的数据库、期刊、会议,分享给大家:(大牛们有补充的就在评论区补充一下,我会加上去。) 1、Elsevier (ScienceDirect OnSite,SDOL...

用朴素贝叶斯对wine数据集分类

该实验的数据集是MostPopular Data Sets(hits since 2007)中的wine数据集,这是是对在意大利同一地区生产的三种不同品种的酒,做大量分析所得出的数据。这些数据包括了三...

算法学习笔记——分治法

一、基本概念 在计算机科学中,分治法是一种很重要的算法。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求...

K-means聚类算法

K-means聚类算法 K-means(K均值)是基于数据划分的无监督聚类算法,也是数据挖掘领域的十大算法之一。 何为聚类算法?在某种程度上可以理解为无监督的分类方法。 聚类算法可以分为哪些部分...

数学之美番外篇:平凡而又神奇的贝叶斯方法

概率论只不过是把常识用数学公式表达了出来。 ——拉普拉斯 记得读本科的时候,最喜欢到城里的计算机书店里面去闲逛,一逛就是好几个小时;有一次,在书店看到一本书,名叫贝叶斯方法。当时数学系的课程还没有...

Stereo Matching文献笔记之(九):经典算法Semi-Global Matching(SGM)之神奇的HMI代价计算~

SGM算法源于《Stereo Processing by Semi-Global Matching and Mutual Information》一文,我认为这篇文章是立体匹配算法中最给力的,放眼KI...

k-means算法MATLAB和opencv代码

上一篇博客写了k-means聚类算法和改进的k-means算法,这篇博客就贴出对应的MATLAB和C++代码。以下是MATLAB代码,实现用k-means进行分割: %%%%%%%%%%%%%%...

Stereo Matching文献笔记之(二):《A Non-Local Cost Aggregation Method for Stereo Matching》读后感~

最近一直在做stereo matching方向的研究,仔细研读了包括局部算法,全局算法,以及半全局算法三个方面的算法文献,对该方向有了比较清晰的了解,这次分享一下我对杨庆雄的经典文献《A Non-Lo...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)