kNN算法--Python3实现

在线公式编辑:http://www.codecogs.com/latex/eqneditor.php
1、算法概述
1)k-近邻算法采用测量不同特征值之间的距离的方法进行分类
2)工作原理:存在一个样本数据集,并且样本集中的每个数据都存在标签。当输入一个没有标签的数据时,将该数据的特征与样本集合中数据对应的特征进行比较(计算距离),然后算法提取样本集合中特征最相似数据的类别标签(一般只选择最近的k个数据,选择k个数据多数属于的类别)。k通常小于20
3)k-近邻的三个基本要素:k值的选择、距离度量、分类决策规则
4)k值的选择:k值小意味着整体模型变得复杂,容易发生过拟合,“学习”的估计误差大
k值大可以减少学习的估计误差,但是学习的近似误差会增大。模型会变简单。
5)距离度量:一般是欧式距离,也可以是别的,如曼哈顿距离
距离公式
当p=2时,为欧式距离,当p=1时为曼哈顿距离。当p无穷大时,为各个坐标距离的最大值。
6)分类决策规则:多数表决。

  • kNN算法过
  • 计算已知类别数据集中的点与当前点的距离(当前点即要测试的数据)
  • 计算距离递增次序排序
  • 选取与当前点距离最小的k个点
  • 确定前k个点所在类别的出现频率
  • 返回上步中出现频率最高的类别作为当前的预测分类。
#求距离
    dataSetSize = dataSet.shape[0]#shape[0]返回dataset的第二维长度
    diffMat=tile(inX,(dataSetSize,1))-dataSet#inX和dataSet的差值
    sqDiffMat=diffMat**2#差值求平方
    sqDistances=sqDiffMat.sum(axis=1)#axis=1是按照行的方向相加,axis=0列相加
    distances=sqDistances**0.5#开方
    # 以上步骤完成了欧式距离的求解

    #排序 找到距离最小点
    sortdDistIndicies=distances.argsort()#argsort是排序,按照有小到大的顺序返回索引号 如[1,5,3],排序输出[1,3,2]
    classCount={} #dict
    for i in range(k):
        voteIlabel = labels[sortdDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) +1
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]
#B=classify0([1.4,1.2],group,labels,3)
#print(B)

#改进约会网站配对效果

#将文本转化为numpy的解析程序
def file2matrix(filename):
    fr = open(filename)
    array0Lines  = fr.readlines()#读取的数据以行显示,包括换行符
    numberOfLines=len(array0Lines)
    returnMat=zeros((numberOfLines,3))#创建返回numpy矩阵
    classLabelVector=[]#标签list
    index=0
    for line in array0Lines:
        line = line.strip()#去掉换行符(回车字符)
        listFromLine=line.split('\t')#切片
        returnMat[index,:]=listFromLine[0:3]#前三个数据存入numpy返回矩阵
        classLabelVector.append(int(listFromLine[-1]))#最后一个数据存入标签
        index+=1
    return returnMat,classLabelVector
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
#datingDataMat
#print('datingDataMat:','\n',datingDataMat)
#print('datingLabels[0:20]:\n',datingLabels[0:20])

#使用Matplotlib创建散点图

import matplotlib
import matplotlib.pyplot as plt
fig=plt.figure()#画图
ax =fig.add_subplot(111)#画布只放一张图
ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*array(datingLabels),15.0*array(datingLabels))##scatter(x,y,s=1,c="g",marker="s",linewidths=0)
#s:散列点的大小,c:散列点的颜色,marker:形状,linewidths:边框宽度
#plt.show()

#准备数据,归一化数值

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))
    return normDataSet,ranges,minVals
#normMat,ranges,minVals=autoNorm(datingDataMat)
#print(normMat)
#print(ranges)
#print(minVals)

#分类器针对约会网站的测试代码

def datingClassTest():
    hoRatio = 0.10
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')#文本转化为矩阵
    normMat, ranges, minVals = autoNorm(datingDataMat)#数据归一化
    m = normMat.shape[0]#行
    numTestVecs=int(m*hoRatio)#测试数据维数
    errorCount=0.0#错误率计数器
    for i in range(numTestVecs):#按行取数据
        classiferReasult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print('the classiferReasult came back with: %d,the real answer is: %d'%(classiferReasult,datingLabels[i]))
        if (classiferReasult!=datingLabels[i]):
            errorCount+=1.0
    print('the total error rate is %f' %(errorCount/float(numTestVecs)))
#datingClassTest()

#使用算法构建完整可用系统
#输入某人信息,得出对对方喜欢程度的预测值

def classifyPerson():
    #定义喜欢程度
    resultList = ['not at all','in small doses','in large doses']
    #输入玩游戏时间、飞行时间、冰激凌消耗量
    percentTats = float(input("percentage of time spent playing video games?"))#input函数允许用户输入文本行命令并但会用户所输入的命令
    ffMiles = float(input("frequent flier miles earned per year?"))
    iceCream = float(input("liters of ice cream comsumed pre year?"))
    #建立KNN原始数据
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
    #特征归一化
    normMat,ranges,minVals=autoNorm(datingDataMat)
    #将输入值建立成三个特征
    inArr = array([ffMiles,percentTats,iceCream])
    #最近邻
    classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
    print("You will probably like the person:%s"%resultList[classifierResult-1])
#classifyPerson()

#手写识别系统

def img2vector(filename):
    returnVect = zeros((1,1024))
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0,32*i+j] = int(lineStr[j])
    return returnVect
testVector = img2vector('testDigits/0_13.txt')
#print(testVector[0,0:31])

#手写数字识别系统的测试代码

def handwritingClassTest():
    hwLabels = []

    #获取训练数据文件目录
    trainingFileList=listdir('trainingDigits')
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))
    for i in range(m):
        fileNameStr= trainingFileList[i]#文件列表
        fileStr = fileNameStr.split('.')[0]#以'.'分割,[0]取序号为0的部分,如0_11.txt,分割后0_11序号为0
        classNumStr = int(fileStr.split('_')[0])#0_11,分割后0序号为0
        hwLabels.append(classNumStr)#依次存放类标签,
        trainingMat[i,:] = img2vector('trainingDigits/%s'% fileNameStr)#调用图像转化函数,并返回矩阵
    testFileList=listdir('testDigits')#测试数据 过程同上
    errorCount = 0.0
    mTest = len(testFileList)
    for j in range(mTest):
        fileNameStr = testFileList[j]
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector('testDigits/%s'%fileNameStr)
        classifierReasult=classify0(vectorUnderTest,trainingMat,hwLabels,3)#调用分类函数,返回分类结果
        print ('the classifier came back with:%d,the real answer is %d'%(classifierReasult,classNumStr))
        if (classifierReasult!=classNumStr):
            errorCount+=1
    print ('\nthe total number of errors is %d'%errorCount )#输出中间不加逗号
    print ('\nthe real error rate is %f'%(errorCount/float(mTest)))
handwritingClassTest()

使用k-近邻算法改进约会网站的配对效果步骤

  • 将文本记录转换为Numpy数据类型
  • 将数据归一化:处理不同取值范围的特征值,消除某些特征取值太大对计算结果产生的影响。
  • 测试算法,构建模型
  • 预测分类

猜你喜欢

转载自blog.csdn.net/fangafangxiaoniu/article/details/78837436