机器学习实战学习笔记(一)分类—kNN算法(python3实现)

来源:互联网 发布:java office转换成pdf 编辑:程序博客网 时间:2024/06/06 02:56

概述

算法采用测量不同特征值之间的距离的方法进行分类。优点是该算法精度高、对异常值不敏感,无数据输入的各种假定;缺点是计算复杂度和空间复杂度都比较高。算法适用的数据类型主要是数值型和标称型。

工作原理

存在一个样本数据集合,也称训练样本集,样本集中的数据都存在标签。在输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据的分类标签。一般来说我们选择样本数据集中前k个最相似的数据。从k个最相似数据中出现次数最多的分类,作为新数据的分类。

算法基本流程
a. 计算已知类别数据集中的点与当前点之间的距离

b. 按照距离递增次序排序

c. 选取与当前点距离最小的k个点

d. 确定前k个点所在类别的出现频率

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

贴上核心代码

"""kNN核心分类器输入inX:用于分类的输入向量dataSet:训练集labels:类别标签向量k:选择邻居的个数"""def classify0(inX,dataSet,labels,k):    #得到训练集的第一纬度的长度(有几行)    dataSetSize=dataSet.shape[0]    #得到特征值之间的差,计算欧式距离    #将输入向量沿行扩展得到差矩阵    diffMat=np.tile(inX,(dataSetSize,1))-dataSet    #差矩阵各个元素乘二次方    sqDiffMat=diffMat**2    #求每一行元素的和并开方得到欧式距离矩阵    sqDistances=sqDiffMat.sum(axis=1)    distances=sqDistances**0.5    #将欧氏距离排序,argsort返回数组值从小到大的索引值    sortedDistIndicies=distances.argsort()    #得到前k个中出现次数最多的类别标签    classCount={}    for i in range(k):        voteLabel=labels[sortedDistIndicies[i]]        #给不同的voteLabel计数        classCount[voteLabel]=classCount.get(voteLabel,0)+1    #sorted第一个参数是一个迭代器,对于字典排序,返回结果是一个元素为元组的列表    #operator模块提供的itemgetter函数用于获取对象的哪些维的数据    sortedClassCount=sorted(classCount.items(),                            key=operator.itemgetter(1),reverse=True)    #返回出现次数最多的voteLabel    return sortedClassCount[0][0]

示例:使用kNN改进约会网站配对效果

分析并处理数据集

样本数据中主要包含三个不同的特征,每年获得的飞行常客里程数,玩视频游戏所耗时间的百分比,每周消费的冰激凌公升数以及标签信息,我们通下面的函数将文本信息转换为python可以分析处理的训练样本矩阵和类标签向量,代码如下“

"""文本数据转换为矩阵数据输入:文件路径输出:训练样本矩阵和类标签向量"""def file2matrix(filename):    fr=open(filename)    #得到样本数据的行数    arrayOfLines=fr.readlines()    numberOfLines=len(arrayOfLines)    #初始化一个0矩阵用于存放样本数据    returnMat=np.zeros((numberOfLines,3))    #定义一个向量用于存放标签    classLabelVector=[]    index=0    #解析数据到矩阵和向量中去    for line in arrayOfLines:        #删除开头和结尾的空白符(包括回车,回车换行和制表符)        line=line.strip()        #根据制表符切割每一行的数据        listFromLine=line.split('\t')        #将列表写到矩阵中        returnMat[index,:]=listFromLine[0:3]        #每一行最后一个是标签        classLabelVector.append(int(listFromLine[-1]))        #到下一行        index+=1    return returnMat,classLabelVector

归一化数值

我们计算的距离的时候,要求每个特征对结果的影响的贡献权值接近,然而飞行里程数远大于另外两个特征,导致其对结果的贡献权值更大,我们利用下述公式处理三个特征值:

       NewValue=(oleValue-min)/(max-min)

这样我们将数据转换到了0和1之间,代码如下:

"""归一化特征值输入:原始特征矩阵输出:元素值属于[0,1]区间的新的特征矩阵"""def autoNorm(dataSet):    #从列选取最值    minVals=dataSet.min(0)    maxVals=dataSet.max(0)    ranges=maxVals-minVals    #初始化一个0矩阵    normDataSet=np.zeros(np.shape(dataSet))    #列数    m=dataSet.shape[0]    normDataSet=dataSet-np.tile(minVals,(m,1))    normDataSet=normDataSet/np.tile(ranges,(m,1))    return normDataSet,ranges,minVals

测试

我们将数据经过上述出来后,计算测试向量的数量,将数据分为测试集合训练集两部分,将其输入到上面的kNN核心分类器中,计算错误率并返回结果,代码如下:

"""测试代码"""def dataingTest():    hoRatio=0.10    datingSet,datainglabels=file2matrix("datingTestSet2.txt")    normMat,ranges,minVals=autoNorm((datingSet))    m=normMat.shape[0]    numTestVecs=int(m*hoRatio)    errorCount=0.0    for i in range(numTestVecs):        classifierResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],datainglabels[numTestVecs:m],3)        print("result is %d, answer is %d"%(classifierResult,datainglabels[i]))        if(classifierResult!=datainglabels[i]):            errorCount+=1.0    print("error rate is %f"%(errorCount/float(numTestVecs)))

然后我们可以写一个主函数,允许用户自己输入三个特征值来进行判断,本文略去

小结

优点:

1.简单好用,容易理解,精度高,理论成熟,既可以用来做分类也可以用来做回归;

2.可用于数值型数据和离散型数据;

3.训练时间复杂度为O(n);无数据输入假定;

4.对异常值不敏感

缺点:

1.计算复杂性高;空间复杂性高;

2.样本不平衡问题(即有些类别的样本数量很多,而其它样本的数量很少;

3.一般数值很大的时候不用这个,计算量太大。但是单个样本又不能太少 否则容易发生误分。

4.最大的缺点是无法给出数据的内在含义。

所以笔者认为在数据明确而且相对适中的时候,kNN算法进行分类效果很好

学习资料github链接



阅读全文
0 0
原创粉丝点击