KNN分类器

                                                                   转载请注明:http://blog.youkuaiyun.com/suky520

理论部分:



评述:

 1)KNN方法主要依据周围有限的临近样本,而不是依靠判别类域的方法来判断所属类别。因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。

 2)当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数,这里可以采用权值的方法(和该样本距离小的邻居权值大)来改进。

 3)该方法的另一个不足之处是计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点。

 4)目前常用的解决方法是事先对已知样本点进行处理,事先去除对分类作用不大的样本。

 5)该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分。


KNN二分类器实例:

数据:数据集有3000个样本,每个样本是三维的,其中两个位是特征,一位是标签。选择前面2500个样本作为训练数据,后面500个样本作为测试数据。这里要求使用KNN来鉴别这些测试数据。

打开数据集

代码实现:

load data1;
double temp;
distance=zeros(2,2500);
k=5;
right=0;

%对500个测试数据,测试每一个样本点类别,并统计正确率
for m=2501:1:3000  %测试循环

    %第一步:求待测点到已知类别的数据集的距离
    for i=1:1:2500
        distance(1,i)=sqrt( (data(1,i)-data(1,m))^2 + (data(2,i)-data(2,m))^2 );
        distance(2,i)=data(3,i);
    end

    %第二步:对距离进行排序(从小到大)
    [distance(1,:),ind]=sort(distance(1,:),2);
    distance(2,:) = distance(2,ind);

    sum1=0;
    sum2=0;

    %第三步:选择前面k个距离对应的点,并且统计各个类别的频数(频率)
    for i=1:1:k
       if(distance(2,i)==1) %类别1(+1)
         sum1=sum1+1;
        else
         sum2=sum2+1;       %类别2(-1)
       end
    end

    %第四步:将出现频率(频率)最大的类别作为测试点的类别。
    %这里在统计正确率
    if(((sum1>sum2)&&(data(3,m)==1))||((sum1<sum2)&&(data(3,m)==-1)))
       right=right+1;
    end

end

arr=right/500

测试结果的正确率:100%(可能是样本问题吧??)

KNN进阶(多类情况):

对于图像数据,如0-9的手写字母识别问题,每个字母的个数近200,图像大小为32x32的0-1矩阵,训练样本近2000,测试样本近1000。

下面是我使用matlab代码实现的。

第一:图像数据转换列向量形式(img2vector.m)

function imgVector=img2vector(filename)
%将32*32的数字图像转换为1024*1的列向量
rows = 32;
cols = 32;
imgVector = zeros(rows * cols,1); %列向量
fid = fopen(filename,'r');
for row=1:rows
    tline = fgetl(fid);  %读取txt文件中一行字符串
    for col=1:cols
        %将字符转换为数字保存到向量中
        imgVector((row-1)*32 + col) = tline(col) - 48; 
    end   
end   
fclose(fid);

第二:加载数据集(包括训练数据和测试数据)loadDataSet.m

%数据的格式:一列代表一个样本(包含了特征以及标签(最后一位))
%得到训练样本集
file = dir('.\digits\trainingDigits\*.txt');
train_x=zeros(32*32,length(file)); %
train_y=zeros(1,length(file));
for n=1:length(file)
    filename = file(n).name;
    label = regexp(filename,'_','split'); %正则法则,按'_'分割字符串
    train_y(n)=cell2mat(label(1)) - 48;   %cell2mat把cell类型转换为数字型
    filename = strcat('.\digits\trainingDigits\',filename);
    train_x(:,n)=img2vector(filename);
end

%得到测试样本集
file = dir('.\digits\testDigits\*.txt');
test_x=zeros(32*32,length(file)); %
test_y=zeros(1,length(file));
for n=1:length(file)
    filename = file(n).name;
    label = regexp(filename,'_','split'); %正则法则,按'_'分割字符串
    test_y(n)=cell2mat(label(1)) - 48;    %cell2mat把cell类型转换为数字型
    filename = strcat('.\digits\testDigits\',filename);
    test_x(:,n)=img2vector(filename);
end

%训练数据
trainData=[train_x ;train_y];
%测试数据
testData=[test_x ; test_y ];
save DATA trainData testData 
    
第三:测试手写字母(testHandWritingClass.m):

clc,clear
tic
%加载数据
load DATA.mat

train_x= trainData(1:end-1,:);  %训练样本
train_y= trainData(end,:);      %训练样本的标签(类别)
test_x = testData(1:end-1,:);   %测试样本
test_y = testData(end,:);       %测试样本的标签(类别)

[n,m]=size(test_x); %m是测试样本的个数
numTestSamples = m;
right = 0;
k=3;
%测试数据
for i = 1:1:numTestSamples
    %knn分类器
    predict = knn_Classify(test_x(:,i), train_x, train_y, k);
    if predict == test_y(i)
        right = right + 1;
    end
end
%精度
accuray = right/numTestSamples
toc
第四:knn分类器(knn_Classify.m)

function  predict = knn_Classify(newInput, dataSet, labels, k)
  %newInput:测试数据(是一个列向量)
  %dataSet: 训练样本集(其中,一列代表一个样本)
  %labels:  训练样本的标签(类别)
  
  %第一步:求待测点到已知类别的数据集的距离
  [n,m]=size(dataSet);
  distance=zeros(2,m);
  for i=1:1:m
     distance(1,i)=sqrt(dot(dataSet(:,i)-newInput,dataSet(:,i)-newInput));
     distance(2,i)=labels(i);
  end
  
  %第二步:对距离进行排序(从小到大)
  [distance(1,:),ind]=sort(distance(1,:),2);
  distance(2,:) = distance(2,ind);  
  
  %第三步:选择前面k个距离对应的点,并且统计各个类别的频数(频率)
  class=unique(labels);      %0-9个类别,unique(去除重复的元素)
  count=zeros(2,length(class));  %用于各个类别的个数    
  for j=1:length(class)
     sum=0;
     %统计在前面k个距离对应点中各个类别出现频数
     for i=1:1:k
       if(distance(2,i)==class(j)) %类别
           sum= sum + 1;                
       end       
     end
     count(:,j) = [sum;class(j)];    
  end  
  
 %第四步:将出现频率(频率)最大的类别作为测试点的类别。
 [val,ind]=max(count(1,:)); %ind是最大值val所在位置
 predict = count(2,ind);
    
    
  

测试结果为:

accuray =

    0.9873

Elapsed time is 61.209153 seconds.


参考1:http://blog.youkuaiyun.com/zouxy09/article/details/16955347

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值