机器学习算法---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

R语言的实现代码如下

library(class)
data(iris)
names(iris)
m1<-knn.cv(iris[,1:4],iris[,5],k=3,prob=TRUE)
attributes(.Last.value)
library(MASS)
m2<-lda(iris[,1:4],iris[,5])  与判别分析进行比较
b<-data.frame(Sepal.Length=6,Sepal.Width=4,Petal.Length=5,Petal.Width=6)
p1<-predict(m2,b,type="class")

C++ 实现 :

//    KNN.cpp     K-最近邻分类算法
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <iostream>
#include <math.h>
#include <fstream>
using namespace std;
////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    宏定义
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
#define  ATTR_NUM  4                        //属性数目
#define  MAX_SIZE_OF_TRAINING_SET  1000      //训练数据集的最大大小
#define  MAX_SIZE_OF_TEST_SET      100       //测试数据集的最大大小
#define  MAX_VALUE  10000.0                  //属性最大值
#define  K  7
//结构体
struct dataVector {
    int ID;                      //ID号
    char classLabel[15];             //分类标号
    double attributes[ATTR_NUM]; //属性
};
struct distanceStruct {
    int ID;                      //ID号
    double distance;             //距离
    char classLabel[15];             //分类标号
};

////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    全局变量
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
struct dataVector gTrainingSet[MAX_SIZE_OF_TRAINING_SET]; //训练数据集
struct dataVector gTestSet[MAX_SIZE_OF_TEST_SET];         //测试数据集
struct distanceStruct gNearestDistance[K];                //K个最近邻距离
int curTrainingSetSize = 0;                                 //训练数据集的大小
int curTestSetSize = 0;                                     //测试数据集的大小
////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    求 vector1=(x1,x2,...,xn)和vector2=(y1,y2,...,yn)的欧几里德距离
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
double Distance(struct dataVector vector1, struct dataVector vector2)
{
    double dist, sum = 0.0;
    for (int i = 0; i < ATTR_NUM; i++)
    {
        sum += (vector1.attributes[i] - vector2.attributes[i])*(vector1.attributes[i] - vector2.attributes[i]);
    }
    dist = sqrt(sum);
    return dist;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    得到gNearestDistance中的最大距离,返回下标
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
int GetMaxDistance()
{
    int maxNo = 0;
    for (int i = 1; i<K; i++)
    {
        if (gNearestDistance[i].distance>gNearestDistance[maxNo].distance) maxNo = i;
    }
    return maxNo;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    对未知样本Sample分类
//
////////////////////////////////////////////////////////////////////////////////////////////////////////
char* Classify(struct dataVector Sample)
{
    double dist = 0;
    int maxid = 0, freq[K], i, tmpfreq = 1;;
    char *curClassLable = gNearestDistance[0].classLabel;
    memset(freq, 1, sizeof(freq));
    //step.1---初始化距离为最大值
    for (i = 0; i < K; i++)
    {
        gNearestDistance[i].distance = MAX_VALUE;
    }
    //step.2---计算K-最近邻距离
    for (i = 0; i < curTrainingSetSize; i++)
    {
        //step.2.1---计算未知样本和每个训练样本的距离
        dist = Distance(gTrainingSet[i], Sample);
        //step.2.2---得到gNearestDistance中的最大距离
        maxid = GetMaxDistance();
        //step.2.3---如果距离小于gNearestDistance中的最大距离,则将该样本作为K-最近邻样本
        if (dist < gNearestDistance[maxid].distance)
        {
            gNearestDistance[maxid].ID = gTrainingSet[i].ID;
            gNearestDistance[maxid].distance = dist;
            strcpy(gNearestDistance[maxid].classLabel, gTrainingSet[i].classLabel);
        }
    }
    //step.3---统计每个类出现的次数
    for (i = 0; i < K; i++)
    {
        for (int j = 0; j < K; j++)
        {
            if ((i != j) && (strcmp(gNearestDistance[i].classLabel, gNearestDistance[j].classLabel) == 0))
            {
                freq[i] += 1;
            }
        }
    }
    //step.4---选择出现频率最大的类标号
    for (i = 0; i<K; i++)
    {
        if (freq[i]>tmpfreq)
        {
            tmpfreq = freq[i];
            curClassLable = gNearestDistance[i].classLabel;
        }
    }
    return curClassLable;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    主函数
//
////////////////////////////////////////////////////////////////////////////////////////////////////////

void main()
{
    char c;
    char *classLabel = "";
    int i, j, rowNo = 0, TruePositive = 0, FalsePositive = 0;
    ifstream filein("iris.data");  //下载数据或者自己编辑
    FILE *fp;
    if (filein.fail()){ cout << "Can‘t open data.txt" << endl; return; }
    //step.1---读文件
    while (!filein.eof())
    {
        rowNo++;//第一组数据rowNo=1
        if (curTrainingSetSize >= MAX_SIZE_OF_TRAINING_SET)
        {
            cout << "The training set has " << MAX_SIZE_OF_TRAINING_SET << " examples!" << endl << endl;
            break;
        }
        //rowNo%3!=0的100组数据作为训练数据集
        if (rowNo % 3 != 0)
        {
            gTrainingSet[curTrainingSetSize].ID = rowNo;
            for (int i = 0; i < ATTR_NUM; i++)
            {
                filein >> gTrainingSet[curTrainingSetSize].attributes[i];
                filein >> c;
            }
            filein >> gTrainingSet[curTrainingSetSize].classLabel;
            curTrainingSetSize++;

        }
        //剩下rowNo%3==0的50组做测试数据集
        else if (rowNo % 3 == 0)
        {
            gTestSet[curTestSetSize].ID = rowNo;
            for (int i = 0; i < ATTR_NUM; i++)
            {
                filein >> gTestSet[curTestSetSize].attributes[i];
                filein >> c;
            }
            filein >> gTestSet[curTestSetSize].classLabel;
            curTestSetSize++;
        }
    }
    filein.close();
    //step.2---KNN算法进行分类,并将结果写到文件iris_OutPut.txt
    fp = fopen("iris_OutPut.txt", "w+t");
    //用KNN算法进行分类
    fprintf(fp, "************************************程序说明***************************************\n");
    fprintf(fp, "** 采用KNN算法对iris.data分类。为了操作方便,对各组数据添加rowNo属性,第一组rowNo=1!\n");
    fprintf(fp, "** 共有150组数据,选择rowNo模3不等于0的100组作为训练数据集,剩下的50组做测试数据集\n");
    fprintf(fp, "***********************************************************************************\n\n");
    fprintf(fp, "************************************实验结果***************************************\n\n");
    for (i = 0; i < curTestSetSize; i++)
    {
        fprintf(fp, "************************************第%d组数据**************************************\n", i + 1);
        classLabel = Classify(gTestSet[i]);
        if (strcmp(classLabel, gTestSet[i].classLabel) == 0)//相等时,分类正确
        {
            TruePositive++;
        }
        cout << "rowNo: ";
        cout << gTestSet[i].ID << "    \t";
        cout << "KNN分类结果:      ";

        cout << classLabel << "(正确类标号: ";
        cout << gTestSet[i].classLabel << ")\n";
        fprintf(fp, "rowNo:  %3d   \t  KNN分类结果:  %s ( 正确类标号:  %s )\n", gTestSet[i].ID, classLabel, gTestSet[i].classLabel);
        if (strcmp(classLabel, gTestSet[i].classLabel) != 0)//不等时,分类错误
        {
            // cout<<"   ***分类错误***\n";
            fprintf(fp, "                                                                      ***分类错误***\n");
        }
        fprintf(fp, "%d-最临近数据:\n", K);
        for (j = 0; j < K; j++)
        {
            // cout<<gNearestDistance[j].ID<<"\t"<<gNearestDistance[j].distance<<"\t"<<gNearestDistance[j].classLabel[15]<<endl;
            fprintf(fp, "rowNo:  %3d   \t   Distance:  %f   \tClassLable:    %s\n", gNearestDistance[j].ID, gNearestDistance[j].distance, gNearestDistance[j].classLabel);
        }
        fprintf(fp, "\n");
    }
    FalsePositive = curTestSetSize - TruePositive;
    fprintf(fp, "***********************************结果分析**************************************\n", i);
    fprintf(fp, "TP(True positive): %d\nFP(False positive): %d\naccuracy: %f\n", TruePositive, FalsePositive, double(TruePositive) / (curTestSetSize - 1));
    fclose(fp);
    return;
}

实验结果:

参考: python 实现 knn分类算法 (Iris 数据集)

时间: 2024-10-07 09:18:18

机器学习算法---KNN的相关文章

机器学习算法&#183;KNN

机器学习算法应用·KNN算法 一.问题描述 验证码目前在互联网上非常常见,从学校的教务系统到12306购票系统,充当着防火墙的功能.但是随着OCR技术的发展,验证码暴露出的安全问题越来越严峻.目前对验证码的识别已经有了许多方法,例如CNN,可以直接输入图片进行识别.验证码分为许多种类,本文以传统的字符验证码作为研究对象,进行图片分割成单一图片作为训练集,构架以测KNN,决策树或者朴素贝叶斯这三个算法为核心的验证码识别算法,进一步体会三个算法的特点. 二.数据准备 2.1数据说明 对于比较简单的字

机器学习算法---kNN算法

kNN-------k-邻近算法 1.kNN是non-parametric分类器,既不做分布式假设,直接从数据估计概率密度: 2.kNN不适用于高维数据 优点: 1.无需估计参数,无需训练: 2.特别适合于多分类问题(对象具有多个标签). 缺点: 1.当样本容量不平衡是,输入有个新样本,该样本的K个邻值中大容量样本占多数,对分类不利: 2.计算量过大,需要计算待分类文本到每个样本的距离. 改进办法: 1.实现对样本属性进行适当删减,删除对结果影响较小的属性: 2.对距离加权,采取和样本距离小的待

常用机器学习算法KNN原理与实践

推荐两篇讲解与实践KNN比较好博客,感谢原作者总结 http://blog.csdn.net/u012162613/article/details/41768407 http://www.cnblogs.com/ybjourney/p/4702562.html

【机器学习算法实现】kNN算法__手写识别——基于Python和NumPy函数库

[机器学习算法实现]系列文章将记录个人阅读机器学习论文.书籍过程中所碰到的算法,每篇文章描述一个具体的算法.算法的编程实现.算法的具体应用实例.争取每个算法都用多种语言编程实现.所有代码共享至github:https://github.com/wepe/MachineLearning-Demo     欢迎交流指正! (1)kNN算法_手写识别实例--基于Python和NumPy函数库 1.kNN算法简介 kNN算法,即K最近邻(k-NearestNeighbor)分类算法,是最简单的机器学习算

机器学习之KNN(k近邻)算法

1.算法介绍k近邻算法是学习机器学习的入门算法,可实现分类与回归,属于监督学习的一种.算法的工作原理是:输入一个训练数据集,训练数据集包括特征空间的点和点的类别,可以是二分类或是多分类.预测时,输入没有类别的点,找到k个与该点距离最接近的点,使用多数表决的方法,得出最后的预测分类. 2.算法优缺点优点:没有高深的数学思想,容易理解,精度高,对异常值不敏感,无数据输入假定:缺点:计算复杂度高,空间复杂度高:理解:因为knn算法是寻找与目标点接近的点,在计算时,异常值与目标点的"距离"会较

scikit-learn中的机器学习算法封装——kNN

接前面 https://www.cnblogs.com/Liuyt-61/p/11738399.html 回过头来看这张图,什么是机器学习?就是将训练数据集喂给机器学习算法,在上面kNN算法中就是将特征集X_train和Y_train传给机器学习算法,然后拟合(fit)出一个模型,然后输入样例到该模型进行预测(predict)输出结果. 而对于kNN来说,算法的模型其实就是自身的训练数据集,所以可以说kNN是一个不需要训练过程的算法. k近邻算法是非常特殊的,可以被认为是没有模型的算法 为了和其

机器学习系列(9)_机器学习算法一览(附Python和R代码)

本文资源翻译@酒酒Angie:伊利诺伊大学香槟分校统计学同学,大四在读,即将开始计算机的研究生学习.希望认识更多喜欢大数据和机器学习的朋友,互相交流学习. 内容校正调整:寒小阳 && 龙心尘 时间:2016年4月 出处:http://blog.csdn.net/han_xiaoyang/article/details/51191386 http://blog.csdn.net/longxinchen_ml/article/details/51192086 声明:版权所有,转载请联系作者并注

机器学习算法之旅

在理解了我们须要解决的机器学习问题之后,我们能够思考一下我们须要收集什么数据以及我们能够用什么算法.本文我们会过一遍最流行的机器学习算法,大致了解哪些方法可用,非常有帮助. 机器学习领域有非常多算法,然后每种算法又有非常多延伸,所以对于一个特定问题,怎样确定一个正确的算法是非常困难的.本文中我想给你们两种方法来归纳在现实中会遇到的算法. 学习方式 依据怎样处理经验.环境或者不论什么我们称之为输入的数据,算法分为不同种类.机器学习和人工智能课本通常先考虑算法能够适应的学习方式. 这里仅仅讨论几个基

【转】常见面试之机器学习算法思想简单梳理

转:http://www.chinakdd.com/article-oyU85v018dQL0Iu.html 前言: 找工作时(IT行业),除了常见的软件开发以外,机器学习岗位也可以当作是一个选择,不少计算机方向的研究生都会接触这个,如果你的研究方向是机器学习/数据挖掘之类,且又对其非常感兴趣的话,可以考虑考虑该岗位,毕竟在机器智能没达到人类水平之前,机器学习可以作为一种重要手段,而随着科技的不断发展,相信这方面的人才需求也会越来越大. 纵观IT行业的招聘岗位,机器学习之类的岗位还是挺少的,国内