首页 > 代码库 > k-近邻算法学习

k-近邻算法学习

参考: http://blog.csdn.net/tjusxh/article/details/51052319

k-近邻算法:简单地说就是采用测量不同特征值之间的距离进行分类的方法。

三个基本要素:K值的选择、距离度量、分类决策规则

优点:精度高、对异常值不敏感、无数据输入假定。

缺点:计算复杂度高、空间复杂度高。

kNN算法的一般流程:

1.导入数据

2.为保证特征权重相同,进行数值归一化

3.距离计算

4.对距离进行排序,选择前K个距离,求出标签出现最多的类别

 

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<sstream>
#include<fstream>
#include<cmath>
using namespace std;

//建立一个数据结构,元素为距离、标签
struct Node{
    double dis;
    double labels;
    Node(){}
    Node(double Dis, double Labels) :dis(Dis), labels(Labels){}
};

bool cmp(Node a, Node b){
    return a.dis<b.dis;
}

//第一步,导入数据
vector<vector<double>> getFile(ifstream&in)
{
    vector<vector<double>> dataMat;            //用于返回的二维容器
    vector<double>item;                        //一维容器,用于压缩到二维容器中
    string s;
    istringstream str;
    while (getline(in, s))                    //将数据按行输入
    {
        str.str(s);
        double tmp;
        while (str >> tmp)
            item.push_back(tmp);
        dataMat.push_back(item);
        item.clear();
        str.clear();
    }
    return dataMat;
}

void printf(vector<vector<double>>data)
{
    int n = data.size();        //这里 n 是样本的数量
    int m = data[0].size();     //特征 + 标签
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
            cout << data[i][j] << " ";
        cout << endl;
    }
}

//数值归一化
vector<vector<double>>makeOne(vector<vector<double>>theData)
{
    vector<vector<double>>dataMat = theData;
    int numRows = theData.size();
    int numColumns = theData[0].size();
    //找出每一列的最大值与最小值
    vector<double>Max;
    vector<double>Min;
    vector<double>ranges;
    for (int i = 0; i < numColumns - 1; i++)    //因为每行最后一个元素是标签,所以要减 1
    {
        double max = theData[i][0];
        double min = theData[i][0];
        for (int j = 1; j < numRows; j++)
        {
            if (theData[j][i] >max)
                max = theData[j][i];
            if (theData[j][i] <min)
                min = theData[j][i];
        }
        Max.push_back(max);
        Min.push_back(min);
    }
    for (int i = 0; i < numColumns - 1; i++)
      for (int j = 0; j < numRows; j++)
      {
          dataMat[j][i] = (theData[j][i] - Min[i]) / (Max[i] - Min[i]);
      }
      return dataMat;
}

//输入待测样本
vector<double>getX(vector<vector<double>>dataMat)    
{
    int m = dataMat[0].size();     
    vector<double>inputX;
    cout << "请输入待测样本 (特征数是" << m - 1 << "个)" << endl;
    for (int i = 0; i < m - 1; i++)
    {
        double temp;
        cin >> temp;
        inputX.push_back(temp);
    }
    return inputX;
}
//计算出 input 到样本点的距离
Node getLabel(vector<double>input, vector<double>Asample)    
{
    Node node1;
    int m = input.size();
    node1.labels = Asample[m];
    double dis = 0;
    for (int i = 0; i < m; i++)
        dis += pow(input[i] - Asample[i], 2.0);
    node1.dis = dis;
    return node1;
}


//对所有的样本点距离进行排序,选择前 K 个,并找出前 K 个出现最多的标签
double makeComp(vector<Node>nodes)
{
    int k;
    double l = 0;
    sort(nodes.begin(), nodes.end(), cmp);             //对距离按升序排序
    cout << "请输入K:" << " ";
    cin >> k;
    int max = 0;                                   
    double label[100] = { 0 };
    for (int i = 0; i<k; i++){                        //前 K 个所处的标签
        label[int(nodes[i].labels)]++;
    }
    for (int i = 0; i < k; i++)                       //用于统计出现次数最多的标签      
    {
        if (max < label[i]){
            l = i;
            max = label[i];
        }
    }
    return l;
}


int main()
{
    vector<vector<double>>dataMat;
    ifstream file("datingTestSet2.txt");  
    dataMat = getFile(file);
    dataMat = makeOne(dataMat);
    int numOfSamples = dataMat.size();
    while (1)
    {
        vector<Node>dis_label;
        vector<double>input = getX(dataMat);             //输入待测例子
        //计算input到每一个样本点的距离,输入为 input,样本点, 输出是:距离,标签
        for (int i = 0; i < numOfSamples; i++)
        {
            Node A = getLabel(input, dataMat[i]);
            dis_label.push_back(A);                               //计算出 input 到所有样本点的距离
        }
        double classfy = makeComp(dis_label);
        cout << classfy << endl;
    }
    return 0;
}

 

k-近邻算法学习