《机器学习实战》第一个算法,k-邻值算法,代码解读

机器学习小白,各位多多交流

def classify0(inX, dataSet, labels, k):  #这个函数就是分类器的函数,要输入4个参数,第一个为测试元素,第二个为数据集,第三个对
    #对应的标签,第四个为K-邻值检测的 K值
    dataSetSize = dataSet.shape[0]  #先求出测试机的行数
    diffMat = tile(inX, (dataSetSize,1)) - dataSet #将测试对象(为一个列表),扩展成一个数组。并和数据集里面的每一个对象进行相减
    sqDiffMat = diffMat**2  # 将相减之后得到的数组进行平方,及数组对应位置的平方,返回的还是一个数组
    sqDistances = sqDiffMat.sum(axis=1) # 按列方向,将平方之后的数字进行相加,得到一个行一样,列为一列的数组
    distances = sqDistances**0.5  #在对求出的数组,每个元素进行开方,来求测试对象和每一个样本集之间的距离
    sortedDistIndicies = distances.argsort()     #然后对求出后的distance 进行排序,并且放回的是这个数在distantces 里面的引索值
    classCount={}          #建立一个空的字典
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]] #取出排前K个数 在原来的位置的引索值,并取得对应引索值下的label值
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1  #dict.get()方法, 如果该label值原来没有的
        # 则新建这个key=lable 的键 并且赋值为0  原来这个dict里面本来就有这个key 的话 那就对应增加这个value的值加1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    #对classCount这个字典先进性items , 通过对items里面的第二个内容的数字大小进行排序,这里即数字,然后为倒叙先大后小,得到一个以元组为元素的列表
    #这里值得注意的是,没办法对字典本身进行排序的,必须先用items方法之后,再进行排序
    return sortedClassCount[0][0] #返回排序中最大元组里面的 标签值

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

def file2matrix(filename):
    fr = open(filename)      #打开名字为filename 的文件名,如果是绝对路径则输入据对路径,如r'D:/xxx.txt',因为本文采用的是相对路径
    numberOfLines = len(fr.readlines())         # 计算改文件的行数,并赋值给 number0fLines
    returnMat = zeros((numberOfLines,3))        # 通过zeros 创建一个行数为 number0flines,列数位3 的初始 0 矩阵 名字为returnMat
    classLabelVector = []                       # 定义了一个classLabelVector 的空列表 用于下面的搜集标签
    index = 0                                    #设置一个值为0 的index 变量
    for line in fr.readlines():            #对文本中的每一个值进行预处理
        line = line.strip()   #先去掉每一行里面首尾的空格及换行符
        listFromLine = line.split('\t')    #然后根据key= '\t'空格符  进行切片   得到的是 每一行的 分开的列表
        returnMat[index,:] = listFromLine[0:3]  # 对相应位置的行进行赋值,赋值的内容为listFromLine 列表的前3个元素,有点像Dict 的赋值
        # 这里需要主要的 因为数组或者矩阵是先行后列的描述,因此如果数字在冒号前面,及对行进行操作,数字在冒号后面即对列进行操作
        classLabelVector.append(int(listFromLine[-1]))  #将listFromLine列表的最后一项及标签,按书序添加到classLabelVector
        #这里对标签项用Int()函数 是为了让标签是一个整体字符串的形式
        index += 1   #然后index 逐步加1  这样就可以 把 txt 里面的所有数据 按照顺序安排带returnMat 中
    return returnMat,classLabelVector   #结果返回 一个数组(前)  一个列表(后)
    
def autoNorm(dataSet):  #因为每个指标的取指范围是不一样的,那么在进行计算的时候,就会造成取值大的指标对结果的影响更大
    #因此需要对原来的数据进行  归一化的处理,类似百分比,这里的dataset 及上一个函数返回的 returnMat
    minVals = dataSet.min(0)  #取出每一列的最小值,axis=0 表示竖的方向,axis=1表示横着的方向,返回的是一个列表
    maxVals = dataSet.max(0)   #取出每一行的最大值
    ranges = maxVals - minVals   #计算出最大值和最小值之间的差值
    normDataSet = zeros(shape(dataSet))  #这一步要不要其实都没关系,只是构建了一个和dataset 一样行列的数组而已
    m = dataSet.shape[0]  #计算出 dataset 的行数,这里是用中括号
    normDataSet = dataSet - tile(minVals, (m,1))   # 先看tile()这个函数,因为minVal 只是一个列表, tile将该列表在行方向重复m次,列方向不动
    #这样出来的就是和dataset 一样 行列的数组,然后通过数组之间的相减实现批量操作
    normDataSet = normDataSet/tile(ranges, (m,1))   #这里的原理和上面一样,只不过是数组之间的相除,只要对应的位置进行相除就可以。
    return normDataSet, ranges, minVals    #最后返回3个只,最后的normDateSet 为归一化之后的数组,ranges是最大最小值相减之后的数组

   
def datingClassTest():  #在进行归一化之后,我们得到了最后可用的数据,也就是我们手头上所有的样本,那么我们需要将样本分成训练样本和验证样本,其实还有一个是测试样本
    hoRatio = 0.10      #这里的hoRation 从后面可知就是需要进行测试的样本百分比
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')  #将函数file2matrix函数返回的数据值和标签列表返回给datingDataMat 和datingLabels
    normMat, ranges, minVals = autoNorm(datingDataMat) #上面得到的数据datingDataMat  被函数autoNorm进行处理,然后换回3个值
    m = normMat.shape[0] #得知normMat 的行数,给m
    numTestVecs = int(m*hoRatio)  #行数的百分之10 整体的数  给numTestVecs
    errorCount = 0.0 #这里设置了一个 错误的基数器
    for i in range(numTestVecs):   #假如全部的样本有1000条,这里的numTestVecs 就是100条,对这100条的数据进行测试
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        #其中classify0 是分类器算法,normMat[i, :]表示normMat中第i行 成为测试数据,normMat的100行下所有数据作为训练数据
        # datingLabels(它是一个列表)是对应100到最后的标签数据, k-近邻算法里面的K值  取前3个结果对象的标签来确定测试样本的特征值
        print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i])
        #打印出 测试结果和 测试数据本身的标签值
        if (classifierResult != datingLabels[i]): errorCount += 1.0
        #如果测试结果和测试数据本身标签纸不一样,则错误数加1
    print "the total error rate is: %f" % (errorCount/float(numTestVecs))
    #打印错误路,因为errorCount是小数浮点数,因此分母也需要改成浮点数格式
    print errorCount

你可能感兴趣的:(Python,python,机器学习,机器学习实战)