您的位置:首页 > 编程语言

《机器学习实战》学习笔记——kNN算法

2015-06-05 17:04 253 查看
《机器学习实战》(MLiA)是一本介绍机器学习的书(的确是废话),和其他书不同的地方在于它给出了python的实现代码,而其他的书籍重在解释理论。我作为一名渣渣,理论就先放一放了。

MLiA的第一章主要介绍了一些概念、常识性的东西,所以不做介绍,这篇文章主要介绍k-近邻算法(kNN)。

kNN算法的优点是精度高,对异常值(离群点)不敏感且不需要训练;缺点是计算复杂度、空间复杂度高

kNN算法的适用范围是数值型和标称型数据

kNN工作原理是:

存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输人没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

kNN算法的算法流程为:

(1).计算已知类别数据集中的点与当前点之间的距离;

(2).按照距离递增次序排序;

(3).选取与当前点距离最小的k个点;

(4).确定前k个点所在类别的出现频率;

(5).返回前k个点出现频率最高的类别作为当前点的预测分类。

既然算法流程已经明确,现在开始构造自己的算法。《MLiA》中采用的是python来构造的算法,原因是机器学习的算法大都需要处理复杂的矩阵运算。鉴于自己的算法处理的数据特征维数并不多,矩阵运算较少,故写了一个简单的c++版本

/*  kNN.cpp
*   @author: Toroto
*/

#include <iostream>
#include <math.h>
using namespace std;

#define DSSIZE 8    //训练集大小

/*
*   数据结构:
*   包含两个特征:x, y
*   及标记:label
*/
struct data{
float x, y;
char label;
};

data D[DSSIZE];     //训练集
float dis[DSSIZE];  //距离数组

//设置训练集:
//{(0,0),(0,0.1),(0,0.2)(0,0.3),(1,1.4),(1,1.5),(1,1.6),(1,1.7)}
void init(int x){
for (int i = 0; i < x; i++){
if (i < 4){
D[i].x = 0;
D[i].label = 'A';
}
else {
D[i].x = 1;
D[i].label = 'B';
}

D[i].y = D[i].x + 0.1 * i;
}
};

/*
*   kNN算法实现:
*   参数:
*       x, y: 目标向量
k:最近邻居的数目
*   返回值:待分类向量的标签
*/
char kNN(float x, float y, int k){
float temp;
data tem;

for (int i = 0; i < DSSIZE; i++){
//计算目标向量到各训练数据的距离
dis[i] = pow(pow(x - D[i].x, 2) + pow(y - D[i].y, 2), 0.5);
//      cout << "i = " << i << "; distance = " << dis[i] << endl;
}

//排序
for (int i = 0; i < DSSIZE; i++){
for (int j = i; j < DSSIZE; j++){
if (dis[i] > dis[j]){
temp = dis[i];
dis[i] = dis[j];
dis[j] = temp;

tem = D[i];
D[i] = D[j];
D[j] = tem;
}
}
}
/*
for (int i = 0; i < DSSIZE; i++){
cout << D[i].x << " " << D[i].y << " " << D[i].label << " " << dis[i] << endl;
}
//*/

int label_A = 0, label_B = 0;

//在给定数目的最近邻居中选择出现次数最多的邻居
for (int i = 0; i < k; i++){
if (D[i].label == 'A') label_A++;
else label_B++;
}

return label_A > label_B ? 'A' : 'B';
}

int main(){
init(DSSIZE);
int k;
float x, y;
char label;

cout << "输入x, y: ";
cin >> x >> y;
cout << "输入k :";
cin >> k;

label = kNN(x * 1.0, y * 1.0, k);
cout << label << endl;

return 0;
};


这样就完成了一个简单版的kNN。

测试:

输入0.1 ,0.2, k = 5,结果如下:



输入0.8, 1.2, k = 5, 结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息