K-近临算法

K-近邻算法百度百科解释为“K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:在特征空间中,如果一个样本附近的k个最近(即特征空间中最邻近)样本的大多数属于某一个类别,则该样本也属于这个类别。”

简单来说KNN就是测量不同特征值之间的距离然后进行分类,属于无监督学习的一种。

本文主要分享一下我学习KNN原理的过程,及KNN的简单描述,阅读本文大约耗时15分钟。

一、KNN的优缺点

优缺点描述
优点精度高、对异常值不敏感、无数据输入假定
缺点计算时间、空间复杂度高
适用数据范围数值型、标称型

二、KNN的一般流程

1、收集数据:可以使用任何方法,一般有条件的可以从Excel、MYsql导入;或利用爬虫获取;或手工输入
2、准备数据:此步骤主要是数据的清洗和结构化
3、分析数据:可以使用任何方法,此步骤也是你为何应用KNN算法的依据,分析数据使用何种方法比使用方法本身更重要!
4、测试算法:计算错误率或计算分类性能
5、使用算法:用KNN判定输入数据属于哪个类,执行后续的操作

三、自己构建KNN算法

当然,可以利用python—sklearn.cluster.KMeans调用KNN,但我主要从原理上理解,所以自行构建一个KNN。

3.1 构建数据集

手工构建一个简单的数据集,包含4个点和1个特征,即:

import numpy as np
group = np.array([[1.0, 1.1],
                  [1.0, 1.],
                  [0.0, 0.0],
                  [0.0, 0.1]])
labels = ['A', 'A', 'B', 'B']

其中labels的个数等于group矩阵的行数,此处我们人为设定前两行数据类型为A,后两行数据类型为B。当然你也可以设定为其他类型,也可以是多种类型,但相应的K值就要改变。接下来我们来实施KNN算法。

3.2 KNN算法原理

前面已经说过KNN算法主要是计算各特征值之间的距离,K代表与当前点距离最小的K个点,因此k值可以人为设定。具体步骤如下:
1、计算已知数据集中的点与当前点的距离
我们学过计算两点之间的距离,利用欧式距离公式,则两个向量点xA和xB之间的距离为

d = ( x A 0 − x B 0 ) 2 + ( x A 1 − x B 1 ) 2 d=\sqrt{(xA_0-xB_0)^2+(xA_1-xB_1)^2} d=(xA0xB0)2+(xA1xB1)2

如点(0,0)和点(3,4)之间的距离为:

( 0 − 3 ) 2 + ( 0 − 4 ) 2 = 5 \sqrt{(0-3)^2+(0-4)^2}=5 (03)2+(04)2 =5

多个特征值时,如点(1,0,0,1)和点(7,6,9,4)之间的距离为:

( 1 − 7 ) 2 + ( 0 − 6 ) 2 + ( 0 − 9 ) 2 + ( 1 − 4 ) 2 \sqrt{(1-7)^2+(0-6)^2+(0-9)^2+(1-4)^2} (17)2+(06)2+(09)2+(14)2

此部分的代码如下:

def classfiy0(inX, dataset, labels, k):
    dataSetSize = dataset.shape[0]
    # print("dataSetSize", dataSetSize)
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataset
    # print("diffMat", diffMat)
    sqDiffMat = diffMat**2
    # print("sqDiffMat", sqDiffMat)
    sqDistances = sqDiffMat.sum(axis=1)
    # print("sqDistances", sqDistances)
    distances = sqDistances**0.5

函数参数解释:

参数意义
inX输入向量
dataset训练样本集
labels标签向量
k选取与当前点距离最小的k个点

在上面代码里,我们首先获取了训练样本集dataset矩阵的行数,利用tile函数构造输入向量相同函数的矩阵,然后计算二者之间的差值,进而平方,求和,最后是开方。
2、按照距离值递增排序,即升序排列
升序排列我们用argsort函数进行,argsort是获取排序后的索引,为什么要获取索引呢?因为我们要利用索引去查找对应的标签,而索引和标签的索引恰恰相同。假设我们的四个点分别为A(1.0,1.1),B(1.0,1.0),C(0.0,0.1),D(0.0,0.0);我们输入向量inX为(0,0),则第一步中输出结果为[2.21,2.0,0.0,0.01],则第2步输出为[2,3,1,0],正好对应相应的标签值。代码如下:

sortedDistIndicies = distances.argsort()

3、获取与当前点距离最小的k个点及出现的频率
前面我们知道k值可以认为设定,因此主要在于如何获取点和对应出现的频率。我们利用dict的get经典方法获取对应的标签和频率,利用for循环进行查找构建dict
代码如下:

classCount = {}
for i in range(k):
    voteILabel = labels[sortedDistIndicies[i]] # 获取对应的标签
    classCount[voteILabel] = classCount.get(voteILabel, 0) + 1 # 获取出现的频率

4、返回前K个点频率出现最高的类别作为输入向量inX的预测值
在这一步,我们继续利用sort函数对classCount.items进行降序排序,排序依据为Value,此时可利用字典排序算法对其排序,常见的有lambda或者operator函数,lambda为:

sortedClassCount = sorted(classCount.items(), key=lambda x:x[1], reverse=True)
return sortedClassCount[0][0]

operator 为:

import operator
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]

四、测试

此时我们输入向量为(0,0),结果预测应该为B,证明分类器没有问题。

# -* encoding:utf-8 -*-
import numpy as np
import operator

group = np.array([[1.0, 1.1],
                  [1.0, 1.],
                  [0.0, 0.0],
                  [0.0, 0.1]])
labels = ['A', 'A', 'B', 'B']
# print(group, labels)

def classfiy0(inX, dataset, labels, k):
    dataSetSize = dataset.shape[0]
    # print("dataSetSize", dataSetSize)
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataset
    # print("diffMat", diffMat)
    sqDiffMat = diffMat**2
    # print("sqDiffMat", sqDiffMat)
    sqDistances = sqDiffMat.sum(axis=1)
    # print("sqDistances", sqDistances)
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()
    classCount = {}
    for i in range(k):
        voteILabel = labels[sortedDistIndicies[i]]
        classCount[voteILabel] = classCount.get(voteILabel, 0) + 1
    # print("classCount", classCount)
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    # print("sortedClassCount", sortedClassCount)
    return sortedClassCount[0][0]

predict = classfiy0([0,0],group,labels,3)
print(predict)

对此一个简单的KNN算法就这样实现了,但如何测试分类器和改进分类器性能,在后续我回陆续推出相应文章。

查看我的其他博客请点击这里

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值