knn的c++版本

找了幾個版本,這個思路最清晰

// knn.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"


//
////////////////////////////////////////////////////////////////////////////////////////////////////////
#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,0,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);
        }
    }
    /// 3、4可以合併優化
    //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);
    system("pause");
    return;
}

以下是測試數據,

5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5.0,3.6,1.4,0.2,Iris-setosa
5.4,3.9,1.7,0.4,Iris-setosa
4.6,3.4,1.4,0.3,Iris-setosa
5.0,3.4,1.5,0.2,Iris-setosa
4.4,2.9,1.4,0.2,Iris-setosa
4.9,3.1,1.5,0.1,Iris-setosa
5.4,3.7,1.5,0.2,Iris-setosa
4.8,3.4,1.6,0.2,Iris-setosa
4.8,3.0,1.4,0.1,Iris-setosa
4.3,3.0,1.1,0.1,Iris-setosa
5.8,4.0,1.2,0.2,Iris-setosa
5.7,4.4,1.5,0.4,Iris-setosa
5.4,3.9,1.3,0.4,Iris-setosa
5.1,3.5,1.4,0.3,Iris-setosa
5.7,3.8,1.7,0.3,Iris-setosa
5.1,3.8,1.5,0.3,Iris-setosa
5.4,3.4,1.7,0.2,Iris-setosa
5.1,3.7,1.5,0.4,Iris-setosa
4.6,3.6,1.0,0.2,Iris-setosa
5.1,3.3,1.7,0.5,Iris-setosa
4.8,3.4,1.9,0.2,Iris-setosa
5.0,3.0,1.6,0.2,Iris-setosa
5.0,3.4,1.6,0.4,Iris-setosa
5.2,3.5,1.5,0.2,Iris-setosa
5.2,3.4,1.4,0.2,Iris-setosa
4.7,3.2,1.6,0.2,Iris-setosa
4.8,3.1,1.6,0.2,Iris-setosa
5.4,3.4,1.5,0.4,Iris-setosa
5.2,4.1,1.5,0.1,Iris-setosa
5.5,4.2,1.4,0.2,Iris-setosa
4.9,3.1,1.5,0.1,Iris-setosa
5.0,3.2,1.2,0.2,Iris-setosa
5.5,3.5,1.3,0.2,Iris-setosa
4.9,3.1,1.5,0.1,Iris-setosa
4.4,3.0,1.3,0.2,Iris-setosa
5.1,3.4,1.5,0.2,Iris-setosa
5.0,3.5,1.3,0.3,Iris-setosa
4.5,2.3,1.3,0.3,Iris-setosa
4.4,3.2,1.3,0.2,Iris-setosa
5.0,3.5,1.6,0.6,Iris-setosa
5.1,3.8,1.9,0.4,Iris-setosa
4.8,3.0,1.4,0.3,Iris-setosa
5.1,3.8,1.6,0.2,Iris-setosa
4.6,3.2,1.4,0.2,Iris-setosa
5.3,3.7,1.5,0.2,Iris-setosa
5.0,3.3,1.4,0.2,Iris-setosa
7.0,3.2,4.7,1.4,Iris-versicolor
6.4,3.2,4.5,1.5,Iris-versicolor
6.9,3.1,4.9,1.5,Iris-versicolor
5.5,2.3,4.0,1.3,Iris-versicolor
6.5,2.8,4.6,1.5,Iris-versicolor
5.7,2.8,4.5,1.3,Iris-versicolor
6.3,3.3,4.7,1.6,Iris-versicolor
4.9,2.4,3.3,1.0,Iris-versicolor
6.6,2.9,4.6,1.3,Iris-versicolor
5.2,2.7,3.9,1.4,Iris-versicolor
5.0,2.0,3.5,1.0,Iris-versicolor
5.9,3.0,4.2,1.5,Iris-versicolor
6.0,2.2,4.0,1.0,Iris-versicolor
6.1,2.9,4.7,1.4,Iris-versicolor
5.6,2.9,3.6,1.3,Iris-versicolor
6.7,3.1,4.4,1.4,Iris-versicolor
5.6,3.0,4.5,1.5,Iris-versicolor
5.8,2.7,4.1,1.0,Iris-versicolor
6.2,2.2,4.5,1.5,Iris-versicolor
5.6,2.5,3.9,1.1,Iris-versicolor
5.9,3.2,4.8,1.8,Iris-versicolor
6.1,2.8,4.0,1.3,Iris-versicolor
6.3,2.5,4.9,1.5,Iris-versicolor
6.1,2.8,4.7,1.2,Iris-versicolor
6.4,2.9,4.3,1.3,Iris-versicolor
6.6,3.0,4.4,1.4,Iris-versicolor
6.8,2.8,4.8,1.4,Iris-versicolor
6.7,3.0,5.0,1.7,Iris-versicolor
6.0,2.9,4.5,1.5,Iris-versicolor
5.7,2.6,3.5,1.0,Iris-versicolor
5.5,2.4,3.8,1.1,Iris-versicolor
5.5,2.4,3.7,1.0,Iris-versicolor
5.8,2.7,3.9,1.2,Iris-versicolor
6.0,2.7,5.1,1.6,Iris-versicolor
5.4,3.0,4.5,1.5,Iris-versicolor
6.0,3.4,4.5,1.6,Iris-versicolor
6.7,3.1,4.7,1.5,Iris-versicolor
6.3,2.3,4.4,1.3,Iris-versicolor
5.6,3.0,4.1,1.3,Iris-versicolor
5.5,2.5,4.0,1.3,Iris-versicolor
5.5,2.6,4.4,1.2,Iris-versicolor
6.1,3.0,4.6,1.4,Iris-versicolor
5.8,2.6,4.0,1.2,Iris-versicolor
5.0,2.3,3.3,1.0,Iris-versicolor
5.6,2.7,4.2,1.3,Iris-versicolor
5.7,3.0,4.2,1.2,Iris-versicolor
5.7,2.9,4.2,1.3,Iris-versicolor
6.2,2.9,4.3,1.3,Iris-versicolor
5.1,2.5,3.0,1.1,Iris-versicolor
5.7,2.8,4.1,1.3,Iris-versicolor
6.3,3.3,6.0,2.5,Iris-virginica
5.8,2.7,5.1,1.9,Iris-virginica
7.1,3.0,5.9,2.1,Iris-virginica
6.3,2.9,5.6,1.8,Iris-virginica
6.5,3.0,5.8,2.2,Iris-virginica
7.6,3.0,6.6,2.1,Iris-virginica
4.9,2.5,4.5,1.7,Iris-virginica
7.3,2.9,6.3,1.8,Iris-virginica
6.7,2.5,5.8,1.8,Iris-virginica
7.2,3.6,6.1,2.5,Iris-virginica
6.5,3.2,5.1,2.0,Iris-virginica
6.4,2.7,5.3,1.9,Iris-virginica
6.8,3.0,5.5,2.1,Iris-virginica
5.7,2.5,5.0,2.0,Iris-virginica
5.8,2.8,5.1,2.4,Iris-virginica
6.4,3.2,5.3,2.3,Iris-virginica
6.5,3.0,5.5,1.8,Iris-virginica
7.7,3.8,6.7,2.2,Iris-virginica
7.7,2.6,6.9,2.3,Iris-virginica
6.0,2.2,5.0,1.5,Iris-virginica
6.9,3.2,5.7,2.3,Iris-virginica
5.6,2.8,4.9,2.0,Iris-virginica
7.7,2.8,6.7,2.0,Iris-virginica
6.3,2.7,4.9,1.8,Iris-virginica
6.7,3.3,5.7,2.1,Iris-virginica
7.2,3.2,6.0,1.8,Iris-virginica
6.2,2.8,4.8,1.8,Iris-virginica
6.1,3.0,4.9,1.8,Iris-virginica
6.4,2.8,5.6,2.1,Iris-virginica
7.2,3.0,5.8,1.6,Iris-virginica
7.4,2.8,6.1,1.9,Iris-virginica
7.9,3.8,6.4,2.0,Iris-virginica
6.4,2.8,5.6,2.2,Iris-virginica
6.3,2.8,5.1,1.5,Iris-virginica
6.1,2.6,5.6,1.4,Iris-virginica
7.7,3.0,6.1,2.3,Iris-virginica
6.3,3.4,5.6,2.4,Iris-virginica
6.4,3.1,5.5,1.8,Iris-virginica
6.0,3.0,4.8,1.8,Iris-virginica
6.9,3.1,5.4,2.1,Iris-virginica
6.7,3.1,5.6,2.4,Iris-virginica
6.9,3.1,5.1,2.3,Iris-virginica
5.8,2.7,5.1,1.9,Iris-virginica
6.8,3.2,5.9,2.3,Iris-virginica
6.7,3.3,5.7,2.5,Iris-virginica
6.7,3.0,5.2,2.3,Iris-virginica
6.3,2.5,5.0,1.9,Iris-virginica
6.5,3.0,5.2,2.0,Iris-virginica
6.2,3.4,5.4,2.3,Iris-virginica
5.9,3.0,5.1,1.8,Iris-virginica

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章