机器学习实战Ch02--KNN

接触ML,DL也有一段时间了,至今还是在入门,也是惭愧的很。所幸时间还有,从基础学起,一步一个脚印的加油吧。

这本书真的很不错,就跟着它来,每过一段时间我会回来交作业的~

kNN.py
'''
优点:精度高,对异常值不敏感,无数据输入假定
缺点:计算复杂度高,空间复杂度高,无法给出数据的内在含义
使用数据范围:数值型和标称型
'''
from numpy import *
import operator
from os import listdir

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

# inX用于分类的输入向量,是一个向量
# dataSet输入的训练样本集,是一个矩阵
# labels标签向量
# k用于选择最近邻居的数目
# labels数目与dataSet的行数相同
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]                      #返回的是dataSet的行数,行数就是样本的数量
    diffMat = tile(inX, (dataSetSize,1)) - dataSet      #矩阵相减
    #inX是个向量,而dataset是个矩阵,两者之间要进行相减的运算,需要把这个向量也补成一个和dataset有相同行数列数的矩阵,
    #tile()的第二个参数,就是(datasetsize,1),这个参数的意思就是把inX补成有datasetsize行数的矩阵。
    #假如inX是(1,2),datasetsize =3,那么经过tile()转换后产生了一个这样的矩阵([1,2],[1,2],[1,2])
    sqDiffMat = diffMat**2                              #平方
    sqDistances = sqDiffMat.sum(axis=1)                 #按行求和
    # sqdiffMat是([1,2],[0,1],[3,4]),axis这个参数影响了对矩阵求和时候的顺序,axis=0是按照列求和,结果为([3.1.7])
    # axis=1是按照行进行求和,结果是([4,7])。
    distances = sqDistances**0.5                        #开方,得到欧氏距离
    sortedDistIndicies = distances.argsort()            #把向量中每个元素进行排序,结果是元素的索引形成的向量
    #例子distance([1,4,3]),经过distance.argsort()之后的结果是([0,2,1]
    classCount={}                                       #存放最终的分类结果及相应的结果投票数
    #投票过程,就是统计前k个最近的样本所属类别包含的样本个数
    for i in range(k):
        # index = sortedDistIndicies[i]是第i个最相近的元素索引,即样本下标
        # voteIlabel = labels[index]是样本index对应的分类结果('A' or 'B')
        voteIlabel = labels[sortedDistIndicies[i]]
        # classCount.get(voteIlabel, 0)返回voteIlabel的值,如果不存在,则返回0
        # 然后将票数增1
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    # 把分类结果进行排序,然后返回得票数最多的分类结果
    # key=operator.itemgetter(1)的意思是按照字典里的第一个排序
    #例子a = [1, 2, 3],b = operator.itemgetter(1),b(a)返回为2
    #b = operator.itemgetter(1, 0),b(a),定义函数b,获取对象的第1个域和第0个的值,返回 (2, 1)
    # reverse=True是降序排序
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0] #返回类别最多的类别

#将文本记录转换为NumPy的解析程序
#输入为矩阵,输出为训练样本矩阵和类标签向量
def file2matrix(filename):
    fr = open(filename)     #打开文档
    numberOfLines = len(fr.readlines())        #得到文件行数
    #fr.readlines()读取行数,存在数组中,导入后每行中用\t隔开,两行之间用\n换行得到文件行数
    returnMat = zeros((numberOfLines,3))        #创建返回NumPy矩阵,numberoflines行,3列的初始化零的矩阵
    classLabelVector = []#定义一个空的数组
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip() #删除()中的内容,这里表示删除空格
        listFromLine = line.split('\t')#以\t分割
        #print(listFromLine)
        returnMat[index,:] = listFromLine[0:3]#把每行前三个元素存入returnMat矩阵中,每行中存储三个
        classLabelVector.append(int(listFromLine[-1]))#存储第四列元素即标签,在数组中append添加,-1表示最后一列
        index += 1
    return returnMat,classLabelVector

#归一化数值,避免某特征值过大,使得权重比例不均匀,对计算结果产生影响。
#autoNorm可以自动将数字特征值转化为0到1区间
def autoNorm(dataSet):
    minVals = dataSet.min(0)#一维数组,值为各项特征(列)中的最小值。参数0使得函数从列中选取最小值
    #print(minVals)
    maxVals = dataSet.max(0)
    #print(maxVals)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet)) #创建与样本集一样大小的零矩阵
    #print(normDataSet)
    m = dataSet.shape[0]#dataSet的行数
    normDataSet = dataSet - tile(minVals, (m,1))#矩阵中所有的值减去最小值
    #tile将原来的一个数组minVals,扩充成了m行1列的数组
    normDataSet = normDataSet/tile(ranges, (m,1))   #矩阵中所有的值除以最大取值范围进行归一化
    return normDataSet, ranges, minVals

#测试算法,样本集中百分之九十的数据用来训练样本,百分之十的样本用来测试分类器kNN.classify0()。
def datingClassTest():
    hoRatio = 0.10      #百分之十的数据用于测试分类器,更改该变量的值可更改参加测试分类器的数据量
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')       #导入数据
    normMat, ranges, minVals = autoNorm(datingDataMat)      #归一化数值
    m = normMat.shape[0]    #得到总行数
    numTestVecs = int(m*hoRatio)    #测试总数据数量,m*hoRatio是一个浮点型,需转化成整形
    errorCount = 0.0    #初试错误率为0
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        #分类器(需要测试的向量,训练样本集(90%),标签集合,K)
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))
        if (classifierResult != datingLabels[i]): errorCount += 1.0     #计数,错误的个数
    print("the total error rate is: %f" % (errorCount/float(numTestVecs)))      #错误率
    print(errorCount)

#对于未来的约会预测函数,输入飞行里程数,玩视频游戏的百分比和冰激凌公升数,可以得到一个是否对他感兴趣的预测,
def classifyPerson():
    resultList=['not at all','in samll doses','in large doses'] #三种感兴趣程度
    percentTats=float(input("percentage of time spent playing video games?"))
    ffMiles=floats=float(input("frequent flier miles earned per year?"))
    iceCream=float(input("liters of ice cream consuned per year?"))#input键盘输入
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt') # 导入数据
    normMat,ranges,minvals=autoNorm(datingDataMat) # 归一化,ranges是归一化的分母
    inArr=array([ffMiles,percentTats,iceCream]) # inArr是归一化之前的datingDataMat数组中的行
    classifierResult=classify0((inArr-minvals)/ranges,normMat,datingLabels,3)#先归一化,然后调用分类函数
    #print(classifierResult)
    print("you will probably like this person:%s"%resultList[classifierResult-1])

#手写体:32*32的黑白图像
#图片转向量,将32*32的二进制图像矩阵转换为1*1024的向量
def img2vector(filename):
    returnVect = zeros((1,1024))
    fr = open(filename)
    for i in range(32):#循环读出文件的前32行
        lineStr = fr.readline()
        for j in range(32):#将每行的前32个字符存储在NumPy数组中
            returnVect[0,32*i+j] = int(lineStr[j])
    return returnVect#返回数组

#手写体
def handwritingClassTest():
    hwLabels = []
    trainingFileList = listdir('trainingDigits')           #导入训练数据
    #print(trainingFileList)
    m = len(trainingFileList)                       #训练数据的总数
    #print(m)
    trainingMat = zeros((m,1024))                   #m行1024列的零向量
    for i in range(m):
        fileNameStr = trainingFileList[i]           #文件名
        fileStr = fileNameStr.split('.')[0]         #取文件名.之前的名字
        classNumStr = int(fileStr.split('_')[0])    #取文件名_之前的名字
        hwLabels.append(classNumStr)
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)    #将对应数据集下的文件一个个的转为向量
        #print(trainingMat[i,:])
    testFileList = listdir('testDigits')            #测试数据
    errorCount = 0.0    
    mTest = len(testFileList)
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3) #利用训练的trainingMat测试
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
        if (classifierResult != classNumStr): errorCount += 1.0
    print("\nthe total number of errors is: %d" % errorCount)
    print("\nthe total error rate is: %f" % (errorCount/float(mTest)))
-----------------------------------------------------------------------------------------------------------------
knn_main.py
import kNN
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from imp import reload


group,labels=kNN.createDataSet()
#print(group)
#print(labels)
#print(kNN.classify0([0,0],group,labels,3))

#散点图
fig=plt.figure()                #建立画板
ax=fig.add_subplot(111)         #添加一个子图,一行一列第一个子块,若括号内为349,则三行四列第9个子块
reload(kNN)
datingDataMat,datingLabels=kNN.file2matrix('datingTestSet2.txt')
#print(datingDataMat)
#ax.scatter(datingDataMat[:,1],datingDataMat[:,2])        # scatter绘制散点图,使用第二列第三列数据
#ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*np.array(datingLabels),15.0*np.array(datingLabels))
ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*np.array(datingLabels),15.0*np.array(datingLabels))
#plt.show()

#归一化数值
normMat,ranges,minVals=kNN.autoNorm(datingDataMat)
#print(normMat)
#print(ranges)
#print(minVals)

#测试算法
#kNN.datingClassTest()

#对于未来的约会预测函数,输入飞行里程数,玩视频游戏的百分比和冰激凌公升数,可以得到一个是否对他感兴趣的预测,
#输入10   10000   0.5
#kNN.classifyPerson()

#手写体
#trainingDigits包含大约2000个例子,每个数字约有200个样本
#testDigits包含大约900个测试数据
testVector=kNN.img2vector('trainingDigits/0_13.txt')
#print(testVector[0,0:31])
#print(testVector[0,32:63])
#print(testVector[0,64:95])
kNN.handwritingClassTest()



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值