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

Python实现KNN算法

2017-09-08 11:18 197 查看

       前段时间学了一段时间的机器学习理论,现在试试使用Python实现一下,本人实java开发,也是刚开始学习Python,记录一下。

本文参考自:http://blog.csdn.net/zouxy09/article/details/16955347

一、kNN算法分析

       K最近邻(k-Nearest Neighbor,KNN)分类算法可以说是最简单的机器学习算法了。它采用测量不同特征值之间的距离方法进行分类。它的思想很简单:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。



        比如上面这个图,我们有两类数据,分别是蓝色方块和红色三角形,他们分布在一个上图的二维中间中。那么假如我们有一个绿色圆圈这个数据,需要判断这个数据是属于蓝色方块这一类,还是与红色三角形同类。怎么做呢?我们先把离这个绿色圆圈最近的几个点找到,因为我们觉得离绿色圆圈最近的才对它的类别有判断的帮助。那到底要用多少个来判断呢?这个个数就是k了。如果k=3,就表示我们选择离绿色圆圈最近的3个点来判断,由于红色三角形所占比例为2/3,所以我们认为绿色圆是和红色三角形同类。如果k=5,由于蓝色四方形比例为3/5,因此绿色圆被赋予蓝色四方形类。从这里可以看到,k的值还是很重要的。

       KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。

       该算法在分类时有个主要的不足是,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。因此可以采用权值的方法(和该样本距离小的邻居权值大)来改进。该方法的另一个不足之处是计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点。目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分[参考机器学习十大算法]。

       总的来说就是我们已经存在了一个带标签的数据库,然后输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似(最近邻)的分类标签。一般来说,只选择样本数据库中前k个最相似的数据。最后,选择k个最相似数据中出现次数最多的分类。其算法描述如下:

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

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

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

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

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

 

二、Python实现

       对于机器学习而已,Python需要额外安装三件宝,分别是Numpy,scipy和Matplotlib。前两者用于数值计算,后者用于画图。安装很简单,直接到各自的官网下载回来安装即可。安装程序会自动搜索我们的python版本和目录,然后安装到python支持的搜索路径下。反正就python和这三个插件都默认安装就没问题了。

       代码如下:"""
knn:k Nearest Neighbors
Input newInput:向量比较现有的数据集(1*n)
数据:尺寸数据集已知向量(N*M个)
标签:标签的数据集(1*m向量)
K:用于比较的邻居数
"""
from numpy import *#Numpy,scipy库负责数值计算,Matplotlib用于画图
import operator
#创建4个样本,包含两种类型的数据集
def createDataSet():
group = array([[1.0, 0.9], [1.0, 1.0], [0.1, 0.2], [0.0, 0.1]])
labels = ['A','A','B','B']
return group,labels
#进行knn运算
def kNNClassify(newInput,dataSet,label,k):
numSamples = dataSet.shape[0]#shape用于矩阵计算 shape[0]计算行数,shape[1]计算列数
#计算点与测试矩阵各点之间的距离
diff = tile(newInput,(numSamples,1)) - dataSet #tile(A,rep)重复A的纬度 然后相减,tile([1,2],(2,2)) 重复顺序为: [1,2] => [[1,2] , [1,2]] => [[1,2,1,2] , [1,2,1,2]]
squaredDiff = diff ** 2 # 平方减去
squaredDist = sum(squaredDiff, axis = 1) # sum(a,axis = 1)axis=1时就是将一个矩阵的每一行向量相加
distance = squaredDist ** 0.5 #开根号,得出点与点之间的距离
sortedDistIndices = argsort(distance)#argsort()函数是将distance中的元素从小到大排列,提取其对应的index(索引),然后输出到sortedDistIndices

#计算在k个点内,各类型的个数
classCount = {} # 定义字典 (可以追加元素)
for i in range(k):
## 步骤3:选择最小k距离
voteLabel = label[sortedDistIndices[i]]

## 第四步:计数时代发生的标签
classCount[voteLabel] = classCount.get(voteLabel, 0) + 1

## 步骤5:最大表决类 返回
maxCount = 0
for key, value in classCount.items():
if value > maxCount:
maxCount = value
maxIndex = key

return maxIndex

dataSet, labels = createDataSet()

testX = array([1.2, 1.0])
k = 3
outputLabel = kNNClassify(testX, dataSet, labels, 3)
print ("输入点:", testX, "属于类型: ", outputLabel)

testX = array([0.1, 0.3])
outputLabel = kNNClassify(testX, dataSet, labels, 3)
print ("输入点:", testX, "属于类型: ", outputLabel)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: