机器学习第一周--K邻近算法,决策树

机器学习第一周

参考链接

https://github.com/wenjunjiecn/Coursera-ML-AndrewNg-Notes/blob/master/markdown/week1.md

https://github.com/apachecn/AiLearning/blob/master/docs/ml

https://space.bilibili.com/97678687/channel/detail?cid=22486

《机器学习实战》


跟着团队已经完成了python基础阶段的学习,发现和一群人一起学习的力量真的很强大,并且也收获了很多。现在就要开始机器学习算法阶段的学习了。第一周的学习内容是

  • 分类问题:K邻近算法
  • 分类问题:决策树

文章目录

  • 机器学习第一周
          • 参考链接
    • 机器学习简介
        • 监督学习
        • 非监督学习
        • 机器学习开发流程
        • numpy快速入门
    • k-邻接算法
        • 什么是K邻接算法?
        • k-近邻算法的一般流程
        • KNN算法伪代码
        • python代码
        • 测试分类器的方法
        • 任务实战--约会网站配对
        • 解析文本数据
        • 分析数据
        • 归一化
          • 归一化python实现
        • 测试分类器
        • 任务实战--手写识别系统
        • 本章python函数小结
            • title函数
            • argsort函数
            • 字典的get()方法
            • 字典的sorted排序
            • 文件的readlines()
            • 关于matplotlib.pyplot.scatter()
        • 第二章小结
    • 决策树
        • 决策树简介
        • 构造决策树
        • 相关概念
        • 划分数据集
        • 递归构建树
        • 绘制决策树
        • 存储决策树
        • 实例练习--预测隐形眼镜类型
        • 本章python函数小结
            • List count()方法
            • python中的del
        • 第三章小结
    • 本周小结

机器学习简介

机器学习是让计算机模拟和实现人类的学习行为,以获取新的知识或技能,重新组织现有得知识结构使之不断 改善自身的性能。

机器学习主要的任务有两类:分类(classification)和回归(regression)

分类就是将数据划分到哦合适的分类中去,例如判断邮件是否是垃圾邮件。

回归就是预测数值型的数据,说起来有点抽象。简单得说。分类的值是离散的,而回归是连续的。

监督学习

监督学习指的就是我们给学习算法一个数据集。这个数据集由“正确答案”组成。例如在分析房价时,我们给了一系列房子的数据,我们给定数据集中每个样本的正确价格,即它们实际的售价然后运用学习算法,算出更多的正确答案。

非监督学习

无监督学习中没有任何的标签或者是有相同的标签或者就是没标签。 针对数据集,无监督学习就能判断出数据有两个不同的聚集簇。这是一个,那是另一个,二者不同。 无监督学习主要包括聚类和密度估计(通过样本紧密程度,估计分组)。

机器学习开发流程

收集数据–>准备数据–>分析数据–>训练数据–>测试数据–>使用算法

numpy快速入门

https://blog.csdn.net/LSGO_MYP/article/details/102988818

k-邻接算法

什么是K邻接算法?

简单的描述,k-近邻算法采用测量不同特征值之间的距离方法进行分类。这里所谓的距离是欧式距离。算法本身通过从样本数据中寻找与待预测的样本数据最接近,也就是距离最短的k个,看看这k个都属于哪一类,类型占比最多的作为预测分类返回。所谓的距离,放在二维空间和三维空间,就是点到点的距离,只是由于数据集,属性可能会更多,所以这里的距离可能建立在超维空间,但是还是那个欧几里得公式.
在这里插入图片描述

k-近邻算法的一般流程

  1. 收集数据:可以使用任何方法。
  2. 准备数据:距离计算所需要的数值,最好是结构化的数据格式。
  3. 分析数据:可以使用任何方法。
  4. 训练算法:此步骤不适用于k-近邻算法。
  5. 测试算法:计算错误率。
  6. 使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输 入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。

KNN算法伪代码

对未知类别属性的数据集中的每个点依次执行以下操作:

  • 计算已知类别数据集中的点与当前点之间的距离;
  • 按照距离递增次序排序;
  • 选取与当前点距离最小的k个点;
  • 确定前k个点所在类别的出现频率;
  • 返回前k个点出现频率最高的类别作为当前点的预测分类。

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
def classify0(inX,dataSet,labels,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()
    classCount={}
    for i in range(k):
        voteIlable=labels[sortedDistIndicies[i]]
        classCount[voteIlable]=classCount.get(voteIlable,0)+1
    sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0]

书上大代码用了iteritems(),这是在python2.x中的方法,在python3.0中items()和iteritems()已近合并了。

>>> import KNN
>>> group,labels=KNN.createDataSet()
>>> group
array([[1. , 1.1],
       [1. , 1. ],
       [0. , 0. ],
       [0. , 0.1]])
>>> labels
['A', 'A', 'B', 'B']
classify0([0,0],group,labels,3)
输出'B'

测试分类器的方法

使用我们已知答案的数据集,得到分类器的错误率——分类器给出错误结果的次数除以测试执行的总数。最好为0,最坏为1.

任务实战–约会网站配对

任务要求

分类:1.不喜欢的人 2.魅力一般的人 3.极具魅力的人

特征:1.每年获得的飞行常客里程数 2.玩视频游戏所耗时间百分比 3.每周消费的冰淇淋公升数

解析文本数据

数据处理是进行机器学习的第一步,之前的一位老师常说garbage in,garbage out。意思就是如果数据本身是一团浆糊不经过分析处理的话,是不会获得好的模型的。

解析数据主要包括,打开文件,读取每一行数据,提取每一列,添加到结果,循环每一列后,返回训练集特征矩阵。

 def file2matrix(filename):
     fr = open(filename)
     array0Lines= fr.readlines()
     numberOfLines=len(array0Lines)
     returnMat=zeros((numberOfLines,3))
     classLabelVector=[]
     index=0
     for line in array0Lines:
         line=line.strip()
         listFromLine=line.split('\t')
         returnMat[index,:]=listFromLine[0:3]
         classLabelVector.append(int(listFromLine[-1]))
         index+=1
     return returnMat,classLabelVector

运行结果

array([[4.0920000e+04, 8.3269760e+00, 9.5395200e-01],
       [1.4488000e+04, 7.1534690e+00, 1.6739040e+00],
       [2.6052000e+04, 1.4418710e+00, 8.0512400e-01],
       ...,
       [2.6575000e+04, 1.0650102e+01, 8.6662700e-01],
       [4.8111000e+04, 9.1345280e+00, 7.2804500e-01],
       [4.3757000e+04, 7.8826010e+00, 1.3324460e+00]])

分析数据

分析数据,可以让我们更加直观的看到数据的特性,我们使用matplotlib.pyplot模块进行特征分析。我们可以使用色彩或者大小标记不同样本的分类。这样更加直观。scatter支持这样一种要求,具体的使用方式,我会在后文python函数小结中总结。

import matplotlib 
import matplotlib.pyplot as plt
import numpy as np
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*np.array(datingLabels),15.0*np.array(datingLabels))
plt.show()

机器学习第一周--K邻近算法,决策树_第1张图片
机器学习第一周--K邻近算法,决策树_第2张图片

上面两图分别是第二特征和第三特征,第一特征和第二特征展示的类别区间。可见,图二我们可以比较直观的分出类别区间

归一化

归一化是数据处理中一个非常重要的概念。通过对距离公式的定义,我们知道,数字差值最大的属性对于距离结果影响最大,但是所有属性都应该是等权重的。我们可以通过归一化实现等权重。所谓的归一化就是把原先的数值范围压缩到一个统一的很小的范围区间内。一般选择压缩在0到1之间,或者-1到1之间。实现起来也很简单。用下面的公式。

newvalue=(oldvalue-min)/(max-min)

max和min分别是最大特征值,最小特征值,也就是value所在列的最大值最小值。

归一化python实现
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

执行结果

array([[0.44832535, 0.39805139, 0.56233353],
       [0.15873259, 0.34195467, 0.98724416],
       [0.28542943, 0.06892523, 0.47449629],
       ...,
       [0.29115949, 0.50910294, 0.51079493],
       [0.52711097, 0.43665451, 0.4290048 ],
       [0.47940793, 0.3768091 , 0.78571804]])

测试分类器

错误率=错误次数/测试总次数

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):
        classifierResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print("the classifier come back with : %d,the real answer is : %d" %(classifierResult,datingLabels[i]))
        if(classifierResult!=datingLabels[i]):errorCount+=1.0
    print( 'the total rate is :%f'%(errorCount/float(numTestVecs)) )       

最终我的测试结果为0.05

最后就是根据建立好的分类器,写用户程序就好了。

任务实战–手写识别系统

之前上课的时候老师有给我们展示过这个数据集分类,这也是非常有名的一个开源数据集。

分类要求:将图片分为数字0-9,进行识别

完成这个任务主要在于数据处理,包括,读取每一个文件转换成当行数组,在这里每一个像素可以看出一个特征,所以一共有1024个特征列。通过该例子,我主要学会了更多地数据提取,处理的方法。

def img2vextor(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
def handwritingClassTest():     --完整程序
    hwLabels=[]
    trainingFileList=listdir('trainingDigits')
    m=len(trainingFileList)
    traingMat=zeros((m,1024))
    for i in range(m):
        fileNameStr=trainingFileList[i]
        fileStr=fileNameStr.split('.')[0]
        classNumStr=int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        traingMat[i,:]=img2vextor('trainingDigits/%s' % fileNameStr)
    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=img2vextor('testDigits/%s' % fileNameStr)
        
        classifierResult=classify0(vectorUnderTest,traingMat,hwLabels,3)
        print("output:%d ,real value: %d" % (classifierResult,classNumStr))
        if (classifierResult!=classNumStr):errorCount+=1.0
    print("errorcount is %d" % (errorCount))
    print("errorrate is:%f" %(errorCount/float(mTest)))

最终错误率0.010571

本章python函数小结

  • title函数

tile(A,n),功能是将数组A重复n次,构成一个新的数组

使用方法

>>> b=[1,3,5]
>>> tile(b,[2,3])
array([[1, 3, 5, 1, 3, 5, 1, 3, 5],
       [1, 3, 5, 1, 3, 5, 1, 3, 5]])
  • argsort函数

argsort()函数是****将a中的元素从小到大排列****,****提取其对应的index(索引),然后输出到b****

a=array([3,2,1,9,-1,6])
b=a.argsort()
b的输出为
array([4, 2, 1, 0, 5, 3], dtype=int64)
  • 字典的get()方法

Python 字典(Dictionary) get() 函数返回指定键的值,如果值不在字典中返回默认值。

dict.get(key, default=None)
  • key – 字典中要查找的键。

  • default – 如果指定键的值不存在时,返回该默认值。

  • 字典的sorted排序
sorted(dic,value,reverse)

dic为比较函数,value 为排序的对象(这里指键或键值),

reverse:注明升序还是降序,True–降序,False–升序(默认)

看了一篇非常好的sortes方法的讲解,里面涉及具体的排序函数(本章算法会使用)甚至多维排序,链接: https://blog.csdn.net/dongtingzhizi/article/details/12068205

  • 文件的readlines()

特点:一次性读取整个文件;自动将文件内容分析成一个行的列表

  • 关于matplotlib.pyplot.scatter()

散点图可以根据标签不同配置不同颜色

https://www.jianshu.com/p/05eeb51c5288

第二章小结

KNN是本书讲解的第一个机器学习算法,理解起来比较简单,knn是最简单也是最有效的算法,但是计算量很大,并且分类效果受到训练数据的影响较大。所以使用一个比较全面反应分类的训练集十分重要。这一章中,我认为主要的难点在于新接触到的各种库,各种函数方法,查阅了很多资料学习,也通过实例的学习,收获很多。

决策树

决策树简介

决策树模型呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是 if-then 规则的集合,也可以认为是定义在特征空间与类空间上的条件概率分布。 下图就是一个简单的决策树。它由判断模块、终止模块、分支组成。

机器学习第一周--K邻近算法,决策树_第3张图片

构造决策树

为了需要构造决策树,我们需要找到当前数据集在划分数据时,起决定性作用的特征,我们选择这样一个特征,划分出最好的结果。

构造决策树伪代码如下:

def createBranch():
    检测数据集中的所有数据的分类标签是否相同:
        If so return 类标签
        Else:
            寻找划分数据集的最好特征(划分之后信息熵最小,也就是信息增益最大的特征)
            划分数据集
            创建分支节点
                for 每个划分的子集
                    调用函数 createBranch (创建分支的函数)并增加返回结果到分支节点中
            return 分支节点

相关概念

熵: 熵指的是体系的混乱的程度,也被定义为信息的期望值。计算熵的公式。熵越高,则说明混合的数据越多。

在这里插入图片描述

信息增益: 在划分数据集前后信息发生的变化称为信息增益。

python计算香农熵,自己跟着书上实现了一下代码

def calcShannonEnt(dataSet):
    numEntries=len(dataSet)
    labelCounts={}
    for featVec in dataSet:
        currentLabel = featVec[-1]
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel]=0
        labelCounts[currentLabel]+=1
    shannonEnt=0.0
    for key in labelCounts:
        prob=float(labelCounts[key])/numEntries
        shannonEnt-=prob*log(prob,2)
    return shannonEnt

通过该函数可以计算出书中例子数据集的熵为0.9709505944546686

划分数据集

def splitDataSet(dataSet,axis,value):
    retDataSet=[]
    for featVec in dataSet:
        if featVec[axis]==value:
            reducedFeatVec=featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet

该函数根据 划分出dataSet中第axis列的值为value的dataSet子集

def chooseBestFeatureToSplit(dataSet):
    numFeatures= len(dataSet[0])-1
    baseEntropy =calcShannonEnt(dataSet)
    bestInfoGain=0.0
    bestFeature=-1
    for i in range(numFeatures):
        featList =[example[i] for example in dataSet] #把每一列特征列提取出来
        uniqueVals=set(featList)   #se可以对列表去重
        newEntropy=0.0
        for value in uniqueVals:
            subDataSet=splitDataSet(dataSet,i,value)
            prob=len(subDataSet)/float(len(dataSet)) #计算出子数据集在数据集上的比例,即选择该分类的概率
            newEntropy+=prob * calcShannonEnt(subDataSet)
        infoGain=baseEntropy-newEntropy
        if (infoGain>bestInfoGain):
            bestInfoGain=infoGain
            bestFeature=i
    return bestFeature

寻找最好的划分特征就是遍历将按每个特征划分一遍数据集,找出信息增益最大的特征返回。

信息增益=原信息熵-划分后的信息熵。

递归构建树

如果数据集已经处理了所有的属性,但类标签依然不是唯一的,我们一般采用多数表决的方法。即找数据集中实例中,类比例最大的类。这个算法和KNN算法中的投票表决类似。

def createTree(dataSet,labels):
    classList=[example[-1] for example in dataSet]
    if classList.count(classList[0])==len(classList):
        return classList[0]
    if len(dataSet[0])==1:
        return majorityCnt(classList)
    bestFeature=chooseBestFeatureToSplit(dataSet)   #找到最好分类特征索引值
    bestFeatureLabel=labels[bestFeature]    #转换为标签名
    myTree={bestFeatureLabel:{}}        #用字典表示决策树,key表示父节点(判断节点),value也是一个字典,里面对元素表示其子节点,可以是最叶子节点,或者下一个判断节点
    del(labels[bestFeature])
    featValues=[example[bestFeature] for example in dataSet]
    uniqueVals=set(featValues)
    for value in uniqueVals:
        subLabels=labels[:]   #python 对于list是传引用,因此,需要建立拷贝
        myTree[bestFeatureLabel][value]=createTree(splitDataSet(dataSet,bestFeature,value),subLabels)
    return myTree

输出结果为

{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

绘制决策树

绘制决策树的目的是为了更加直观的展示决策树。实际在分类过程中是不需要的。因为python中没有专门画树图的模块,因此,需要使用的matplotlib结合annotate注释展示,树形图。其实还挺繁琐的。

以下是我绘制的结果,代码参考,《机器学习实战》

机器学习第一周--K邻近算法,决策树_第4张图片

存储决策树

使用Python模块pickle序列化对象,就可以将序列化对象保存在磁盘上了。书上的部分不适用python3。根据相关错误信息,进行调整。

def storeTree(inputTree,filename):    
    import pickle
    fw = open(filename,'wb')   #以二进制写模式打开文件,注意必须要是二进制模式
    pickle.dump(inputTree,fw)
    fw.close()

def grabTree(filename):
    import pickle
    fr = open(filename,'rb')
    return pickle.load(fr)

执行完写后,会看到目录下多出一个txt文件。这样决策树就被保存下来了,下一次使用决策树分类的时候,就不需要重新构建决策树了。

实例练习–预测隐形眼镜类型

(1) 收集数据:提供的文本文件。 
(2) 准备数据:解析tab键分隔的数据行。 
(3) 分析数据:快速检查数据,确保正确地解析数据内容,使用createPlot()函数绘制 最终的树形图。 
(4) 训练算法:使用createTree()函数。  
(5) 测试算法:编写测试函数验证决策树可以正确分类给定的数据实例。
(6) 使用算法:存储树的数据结构,以便下次使用时无需重新构造树。 

通过本例子的学习,学到了使用列表生成器极其简单的读取文件数据生成数据集的方法

fr=open('lenses.txt')
lenses=[inst.strip().split('\t') for inst in fr.readlines()]
生成的决策树
{'tearRate': {'normal': {'astigmatic': {'no': {'age': {'young': 'soft',
      'pre': 'soft',
      'presbyopic': {'prescript': {'myope': 'no lenses', 'hyper': 'soft'}}}},
    'yes': {'prescript': {'myope': 'hard',
      'hyper': {'age': {'young': 'hard',
        'pre': 'no lenses',
        'presbyopic': 'no lenses'}}}}}},
  'reduced': 'no lenses'}}

机器学习第一周--K邻近算法,决策树_第5张图片

本章python函数小结

  • List count()方法

count() 方法用于统计某个元素在列表中出现的次数。

list.count(obj)

obj – 列表中统计的对象。

  • python中的del

del语句作用在变量上,而不是数据对象上 。 python有GC机制 ,只有作用在数据上的引用数为零时,数据对象才会被清楚

https://www.jianshu.com/p/ac0ceeaa8bd8

  • python中的append和extend
a=[1,2]
b=[3,4]
a.append(b)
a
-------------
[1, 2, [3, 4]]
a=[1,2]
b=[3,4]
a.extend(b)
a
--------------
[1, 2, 3, 4]

注意这两个方法都会修改原列表

第三章小结

从构建决策树的原理来看,决策时就是不断在寻找最优的特征,将数据集进行划分,并将数据集向子节点传递,如果子节点的实例都在一个类别里面了,则不再进行划分,这就是最终的叶节点。否则,递归继续划分。如果所有特征都用完了,那么就采用多数投票方式决定其类别。在本章节通过一些简单的例子,让我掌握了决策树python的实现方法。同时也学习了使用matplotlib绘制树形图,是一个新知识点,需要一定的构造技巧,还是有难度的。

本周小结

虽然之前也有接触一些机器学习的理念,但是都是从数学层面上理解。很少使用代码去实现。而这本书最大的特点就是以python实战机器学习为主线,让我通过另外一种更加深入的方式学习算法,对学习、理解、应用机器学习算法,以及巩固拓展python语法都有非常大的帮助。这周学习的两个概念,在原理上比较好理解,但是其python实现过程中还是能遇到不少问题的。但也在解决这些问题的过程中,收获了很多。在学习中,也发现对matplotlib了解还不够,之后需要专门总结一下相关知识。

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