K近邻算法

概述

该算法采用测量不同特征值之间的距离方法进行分类。

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

缺点:计算复杂度高,每次测试样本中的一个数据都要和训练样本所有数据进行距离计算,所以耗费的时间长,效率不高。空间复杂都高,需要存储大量数据,占用大量存储空间

使用数据范围:数值型,标称型(标称型数据要转化为数字型)

工作原理:算法要求存在一个训练样本数据集合,每个数据都有一个分类标签。输入测试数据后,将新输入样本每个特征值与训练样本特征进行比较,提取出训练样本中特征最相似数据的分类标签,而k表示提取出的分类标签数,可以自定义,根据计算错误率选择最优k值,最后在k个最相似数据中选择出现次数最多的分类,最为新数据的分类

算法一般流程

(1)收集数据:任何数据收集方法

(2)准备数据:将收集的数据整理为符合算法要求的结构化的数据格式

(3)分析数据:任何方法

(4)训练算法:不适用与K近邻算法

(5)测试算法:计算错误率

(6)使用算法:针对约会网站的数据分类,手写数字识别

准备数据:使用python导入数据

 

from numpy import *
import operator #标准函数操作
def createDataSet():
    group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]]) #矩阵,特征值量化,两个特征值
    labels = ['A', 'A', 'B', 'B'] # 列表,上述特征值对应的分类标签    return group, labels

 

我这里是使用的python3.6版本,个人喜欢用较新版本。注意:训练样本特征值以矩阵形式存储,行向量代表一个样本的特征数据,列向量代表一个特征的所有样本值(切记)

实施K近邻算法

def classify0(inx,dataSet,labels,k):# inx为用于分类的输入向量,dataSet为训练样本集,labels为标签向量
    dataSetSize=dataSet.shape[0]
    diffMat=tile(inx,(dataSetSize,1))-dataSet
    #tile()函数将inx进行dataSetSize行,1列重复输出,最后减去dataSet训练集对应的数据
    sqDiffMat=diffMat**2 #矩阵中每个数据点的平方
    sqDistance=sqDiffMat.sum(axis=1) #axis=1表示计算矩阵每一行行向量的和
    Distance=sqDistance**0.5 #行向量,转化为行向量
    sortDistIndicies=Distance.argsort() #从小到大排序,返回排序后的数据点在原Distance中的索引
    classCount={}
    for i in range(k):
        Votelabel=labels[sortDistIndicies[i]]
        classCount[Votelabel]=classCount.get(Votelabel,0)+1;#0为默认值
        print(classCount)
        sortClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)#升序,sortClassCount为列表
        return sortClassCount[0][0]

算法返回了一个新输入数据的分类结果,新数据与样本的相似性在这里用欧式距离公式衡量,即向量间的距离公式。为了预测数据所在分类,可以使用一下命令:

group,labels=createDataSet()
print(classify0([0,0],group,labels,4))

分类器的性能(分类效果)受到多种因素的影响,如分类器设置,数据集等,为了测试分类器的效果,我们可以用分类器给出的测试结果与真实结果进行比较,计算出错误率——错误次数除以总的测试执行次数。

以改进约会网站的配对效果为例

数据来源链接:https://www.manning.com/books/machine-learning-in-action

要是我们想看一下数据的分布情况,可以用Matplotlib创建散点图

import matplotlib
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],20*array(datinglabels),15*array(datinglabels))
plt.show()

准备数据:数值归一化

如果两特征值的数据大小相差很大时,我们可以用归一化将特征值转化为0到1之间

newValue=(oldValue-min)/(max-min)

下面是归一化特征值的代码:

def autoNorm(dataSet):
    minVals = dataSet.min(0)#每列选取最小数
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - tile(minVals, (m,1))
    normDataSet = normDataSet/tile(ranges, (m,1))   #element wise divide
    return normDataSet, ranges, minVals#返回归一化后的数据矩阵,每个特征值的变动大小,特征值的最小值

测试算法:验证分类器

def datingClassTest():
    hoRatio=0.1
    datingDataMat,datinglabels=file2matrix('datingTestSet.txt')
    normMat,rangs,minVals=autoNorm(datingDataMat)
    m=normMat.shape(0)
    numTestVecs=int(m*hoRatio)
    errorCount=0.0;
    for i in range(numTestVecs):
        classifierResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],datinglabels[numTestVecs:m],3)
        if (classifierResult!=datinglabels[i]):
            errorCount+=1;
    print(errorCount/float(numTestVecs))#输出错误率

使用算法:构建完整的可用系统

通过下面的函数,用户可以输入三个特征值,程序会自动给出预测值

def classPerson():
    resultList = ['not at all', 'in small doses', 'in large doses']
    percentTats = float(input("percentage of time spent playing video games?"))
    ffMiles = float(input("frequent flier miles earned per year?"))
    iceCream = float(input("liters of ice cream consumed per year?"))
    datingDataMat, datinglabels = file2matrix('datingTestSet2.txt')
    normMat, rangs, minVals = autoNorm(datingDataMat)
    inArr=array([ffMiles,percentile,iceCream])
    classifierResult=classify0((inArr-minVals)/rangs,normMat,datinglabels,3)
    print(resultList[classifierResult-1])

以上就是K近邻算法及其使用,该算法要求有接近实际数据的训练样本数据,同时,出了上面的缺点以外,该算法还有一个缺陷:无法给出任何数据的基础结构信息,因此我们不能知晓平均实例样本和典型样本具有的特征

 如有转载本博文章,请注明出处。您的支持是我的动力!文章部分内容来自互联网,本人不负任何法律责任。

posted @ 2017-10-31 11:52  冷漠的卫庄  阅读(536)  评论(0编辑  收藏  举报