KNN分类器

该部分为转载部分

KNN最邻近规则,主要应用领域是对未知事物的识别,即判断未知事物属于哪一类,判断思想是,基于欧几里得定理,判断未知事物的特征和哪一类已知事物的的特征最接近;

K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 KNN方法虽然从原理上也依赖于极限定理,但在类别决策时,只与极少量的相邻样本有关。由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
  KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,就可以得到该样本的属性。更有用的方法是将不同距离的邻居对该样本产生的影响给予不同的权值(weight),如权值与距离成正比(组合函数)。
  该算法在分类时有个主要的不足是,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。 该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。该方法的另一个不足之处是计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点。目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分。

K-NN可以说是一种最直接的用来分类未知数据的方法。基本通过下面这张图跟文字说明就可以明白K-NN是干什么的

简单来说,K-NN可以看成:有那么一堆你已经知道分类的数据,然后当一个新数据进入的时候,就开始跟训练数据里的每个点求距离,然后挑离这个训练数据最近的K个点看看这几个点属于什么类型,然后用少数服从多数的原则,给新数据归类。

 

算法步骤:

step.1---初始化距离为最大值

step.2---计算未知样本和每个训练样本的距离dist

step.3---得到目前K个最临近样本中的最大距离maxdist

step.4---如果dist小于maxdist,则将该训练样本作为K-最近邻样本

step.5---重复步骤2、3、4,直到未知样本和所有训练样本的距离都算完

step.6---统计K-最近邻样本中每个类标号出现的次数

step.7---选择出现频率最大的类标号作为未知样本的类标号

 

 

KNN的matlab简单实现代码

function target=KNN(in,out,test,k)
% in:       training samples data,n*d matrix
% out: training samples' class label,n*1
% test:     testing data
% target:   class label given by knn
% k:        the number of neighbors
ClassLabel=unique(out);
c=length(ClassLabel);
n=size(in,1);
% target=zeros(size(test,1),1);
dist=zeros(size(in,1),1);
for j=1:size(test,1)
    cnt=zeros(c,1);
    for i=1:n
        dist(i)=norm(in(i,:)-test(j,:));
    end
    [d,index]=sort(dist);
    for i=1:k
        ind=find(ClassLabel==out(index(i)));
        cnt(ind)=cnt(ind)+1;
    end
    [m,ind]=max(cnt);
    target(j)=ClassLabel(ind);
end

 下面是基于opencv的一个实例:




#include "opencv/ml.h"

#include "opencv/highgui.h"
#include<iostream>


#include<opencv2\ml\ml.hpp>
#include<opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
//k为分级,0~9,分类完成后,accurency均大于等于5。
const int K = 9;
int i, j, k, accuracy;
float response;
int train_sample_count = 100;
//CvRNG rng_state = cvRNG(-1);
CvRNG rng_state(-1);//整形随机数产生,取-1时最大值取0xffffffff
CvMat* trainData = cvCreateMat(train_sample_count, 2, CV_32FC1);//数据,该处为点坐标,为二维数据
CvMat* trainClasses = cvCreateMat(train_sample_count, 1, CV_32FC1);//相对应的数据分类
IplImage* img = cvCreateImage(cvSize(500, 500), 8, 3);
float _sample[2];
CvMat sample = cvMat(1, 2, CV_32FC1, _sample);
cvZero(img);




RNG rng(1);

double a = (double)rng_state;
double b = (int)rng_state;
//cout << a << endl << b << endl;






CvMat trainData1, trainData2, trainClasses1, trainClasses2;


// form the training samples
cvGetRows(trainData, &trainData1, 0, train_sample_count / 2);
cvRandArr(&rng_state, &trainData1, CV_RAND_NORMAL, cvScalar(200, 200), cvScalar(50, 50));
cvShowImage("img1", &trainData1);
//cout << trainData1.cols << endl << trainData1.rows << endl;




cvGetRows(trainData, &trainData2, train_sample_count / 2, train_sample_count);
cvRandArr(&rng_state, &trainData2, CV_RAND_NORMAL, cvScalar(300, 300), cvScalar(50, 50));


cvGetRows(trainClasses, &trainClasses1, 0, train_sample_count / 2);
cvSet(&trainClasses1, cvScalar(1));


cvGetRows(trainClasses, &trainClasses2, train_sample_count / 2, train_sample_count);
cvSet(&trainClasses2, cvScalar(2));
for (int i = 1; i < 101; i++)


{
float* pData=trainData->data.fl + i*trainData->step / 4;
for (int j = 0; j < 2; j++)
{
cout << *(pData + j - trainData->step / 4)<<" ";
}
cout << endl;
}
//Mat img1(trainData);
//Rect roi(0, 0, 1, train_sample_count / 2);
//Mat img=img1(roi);
//cv::imshow("img", img1);
// learn classifier
CvKNearest knn(trainData, trainClasses, 0, false, K);//训练完成
CvMat* nearests = cvCreateMat(1, K, CV_32FC1);


for (i = 0; i < img->height; i++)
{
for (j = 0; j < img->width; j++)
{
sample.data.fl[0] = (float)j;
sample.data.fl[1] = (float)i;


// estimates the response and get the neighbors' labels
response = knn.find_nearest(&sample, K, 0, 0, nearests, 0);


// compute the number of neighbors representing the majority
for (k = 0, accuracy = 0; k < K; k++)
{
if (nearests->data.fl[k] == response)
accuracy++;
}
// highlight the pixel depending on the accuracy (or confidence)



/*
cvSet2D(img, i, j, response == 1 ?
(accuracy > 5 ? CV_RGB(180, 0, 0) : CV_RGB(180, 120, 0)) :
(accuracy > 5 ? CV_RGB(0, 180, 0) : CV_RGB(120, 120, 0)));
*/

if (accuracy < 6)
{

//cout << response << " "<<accuracy<<endl;
}
cvSet2D(img, i, j, response == 1 ? CV_RGB(accuracy * 25, 0, 255 - accuracy * 25) : CV_RGB(255 - accuracy * 25, 0, accuracy * 25));

}
}
cvShowImage("result", img);
// display the original training samples
for (i = 0; i < train_sample_count / 2; i++)
{
CvPoint pt;
pt.x = cvRound(trainData1.data.fl[i * 2]);
pt.y = cvRound(trainData1.data.fl[i * 2 + 1]);
cvCircle(img, pt, 2, CV_RGB(255, 0, 0), CV_FILLED);
pt.x = cvRound(trainData2.data.fl[i * 2]);
pt.y = cvRound(trainData2.data.fl[i * 2 + 1]);
cvCircle(img, pt, 2, CV_RGB(0, 255, 0), CV_FILLED);
}


cvNamedWindow("classifier result", 1);
cvShowImage("classifier result", img);
cvWaitKey(0);


cvReleaseMat(&trainClasses);
cvReleaseMat(&trainData);
return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值