机器学习实践笔记3(树和随机森林)

的优点是,在一个决策树的形式数据是easy理解。和kNN最大的缺点是数据的内在含义,不能给予。

1:这个概念很简单文字说明

决策树的类型有非常多。有CART、ID3和C4.5等。当中CART是基于基尼不纯度(Gini)的。这里不做具体解释,而ID3和C4.5都是基于信息熵的,它们两个得到的结果都是一样的。本次定义主要针对ID3算法。以下我们介绍信息熵的定义。

事件ai发生的概率用p(ai)来表示。而-log2(p(ai))表示为事件ai的不确定程度,称为ai的自信息量,sum(p(ai)*I(ai))称为信源S的平均信息量—信息熵。

决策树学习採用的是自顶向下的递归方法,其基本思想是以信息熵为度量构造一棵熵值下降最快的树,到叶子节点处的熵值为零。此时每一个叶节点中的实例都属于同一类。

ID3的原理是基于信息熵增益达到最大。设原始问题的标签有正例和负例,p和n表示其对应的个数。则原始问题的信息熵为

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTHU1OTcyMDM5MzM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

当中N为该特征所取值的个数。比方{rain,sunny},则N即为2

Gain = BaseEntropy – newEntropy

ID3的原理即使Gain达到最大值。信息增益即为熵的降低或者是数据无序度的降低。

ID3易出现的问题:假设是取值很多其它的属性。更easy使得数据更“纯”(尤其是连续型数值),其信息增益更大,决策树会首先挑选这个属性作为树的顶点。结果训练出来的形状是一棵庞大且深度非常浅的树,这种划分是极为不合理的。

此时能够採用C4.5来解决

C4.5的思想是最大化Gain除以以下这个公式即得到信息增益率:

当中底为2

2:python代码的实现

(1)   计算信息熵

##计算给定数据集的信息熵
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)   #以2为底数求对数
    return shannonEnt

(2)   创建数据集

#创建数据
def createDataSet():
    dataSet = [[1,1,'yes'],
               [1,1,'yes'],
               [1,0,'no'],
               [0,1,'no'],
               [0,1,'no']]
    labels = ['no surfacing', 'flippers']
    return dataSet, labels

(3)   划分数据集

#根据特征划分数据集  axis代表第几个特征  value代表该特征所相应的值  返回的是划分后的数据集
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

(4)   选择最好的特征进行划分

#选择最好的数据集(特征)划分方式  返回最佳特征下标
def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0]) - 1   #特征个数
    baseEntropy = calcShannonEnt(dataSet)
    bestInfoGain = 0.0; bestFeature = -1
    for i in range(numFeatures):   #遍历特征 第i个
        featureSet = set([example[i] for example in dataSet])   #第i个特征取值集合
        newEntropy= 0.0
        for value in featureSet:
            subDataSet = splitDataSet(dataSet, i, value)
            prob = len(subDataSet)/float(len(dataSet))
            newEntropy += prob * calcShannonEnt(subDataSet)   #该特征划分所相应的entropy
        infoGain = baseEntropy - newEntropy
        if infoGain > bestInfoGain:
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature

注意:这里数据集须要满足下面两个办法:

<1>全部的列元素都必须具有同样的数据长度

<2>数据的最后一列或者每一个实例的最后一个元素是当前实例的类别标签。

(5)   创建树的代码

Python用字典类型来存储树的结构  返回的结果是myTree-字典

#创建树的函数代码   python中用字典类型来存储树的结构 返回的结果是myTree-字典
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)       #遍历全然部的特征时返回出现次数最多的
    bestFeat = chooseBestFeatureToSplit(dataSet)
    bestFeatLabel = labels[bestFeat]
    myTree = {bestFeatLabel:{}}
    del(labels[bestFeat])
    featValues = [example[bestFeat] for example in dataSet]    #得到的列表包括全部的属性值
    uniqueVals = set(featValues)
    for value in uniqueVals:
        subLabels = labels[:]
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
    return myTree

当中递归结束当且仅当该类别中标签全然同样或者遍历全部的特征此时返回次数最多的

当中当全部的特征都用完时,採用多数表决的方法来决定该叶子节点的分类,即该叶节点中属于某一类最多的样本数,那么我们就说该叶节点属于那一类!。代码例如以下:

#多数表决的方法决定叶子节点的分类 ----  当所有的特征所实用完时仍属于多类
def majorityCnt(classList):
    classCount = {}
    for vote in classList:
        if vote not in classCount.key():
            classCount[vote] = 0;
        classCount[vote] += 1
    sortedClassCount = sorted(classCount.iteritems(), key = operator.itemgetter(1), reverse = True)  #排序函数 operator中的
    return sortedClassCount[0][0]

即为假设数据集已经处理了全部的属性。可是类标签依旧不是唯一的,此时我们要决定怎样定义该叶子节点,在这样的情况下。我们通常採用多数表决的方法来决定该叶子节点的分类。

(6)   使用决策树运行分类

#使用决策树运行分类
def classify(inputTree, featLabels, testVec):
    firstStr = inputTree.keys()[0]
    secondDict = inputTree[firstStr]
    featIndex = featLabels.index(firstStr)   #index方法查找当前列表中第一个匹配firstStr变量的元素的索引
    for key in secondDict.keys():
        if testVec[featIndex] == key:
            if type(secondDict[key]).__name__ == 'dict':
                classLabel = classify(secondDict[key], featLabels, testVec)
            else: classLabel = secondDict[key]
    return classLabel

注意递归的思想非常重要。

(7)   决策树的存储

构造决策树是一个非常耗时的任务。

为了节省计算时间,最好可以在每次运行分类时调用已经构造好的决策树。

为了解决问题,须要使用python模块pickle序列化对象,序列化对象可以在磁盘上保存对象。并在须要的时候读取出来。

#决策树的存储
def storeTree(inputTree, filename):         #pickle序列化对象。能够在磁盘上保存对象
    import pickle
    fw = open(filename, 'w')
    pickle.dump(inputTree, fw)
    fw.close()

def grabTree(filename):               #并在须要的时候将其读取出来
    import pickle
    fr = open(filename)
    return pickle.load(fr)

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTHU1OTcyMDM5MzM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

3:matplotlib 注解

Matplotlib提供了一个注解工具annotations,很实用,它能够在数据图形上加入文本凝视。

注解通经常使用于解释数据的内容。

这段代码我也没看懂,所以仅仅给出书上代码

# -*- coding: cp936 -*-
import matplotlib.pyplot as plt

decisionNode = dict(boxstyle = 'sawtooth', fc = '0.8')
leafNode = dict(boxstyle = 'round4', fc = '0.8')
arrow_args = dict(arrowstyle = '<-')

def plotNode(nodeTxt, centerPt, parentPt, nodeType):
    createPlot.ax1.annotate(nodeTxt, xy = parentPt, xycoords = 'axes fraction',                            xytext = centerPt, textcoords = 'axes fraction',                            va = 'center', ha = 'center', bbox = nodeType,                             arrowprops = arrow_args)

# 使用文本注解绘制树节点
def createPlot():
    fig = plt.figure(1, facecolor = 'white')
    fig.clf()
    createPlot.ax1 = plt.subplot(111, frameon = False)
    plotNode('a decision node', (0.5,0.1), (0.1,0.5), decisionNode)
    plotNode('a leaf node', (0.8, 0.1), (0.3,0.8), leafNode)
    plt.show()

#获取叶子节点数目和树的层数
def getNumLeafs(myTree):
    numLeafs = 0
    firstStr = myTree.keys()[0]
    secondDict = myTree[firstStr]
    for key in secondDict.keys():
        if(type(secondDict[key]).__name__ == 'dict'):
            numLeafs += getNumLeafs(secondDict[key])
        else: numLeafs += 1
    return numLeafs

def getTreeDepth(myTree):
    maxDepth = 0
    firstStr = myTree.keys()[0]
    secondDict = myTree[firstStr]
    for key in secondDict.keys():
        if(type(secondDict[key]).__name__ == 'dict'):
            thisDepth = 1+ getTreeDepth(secondDict[key])
        else: thisDepth = 1
        if thisDepth > maxDepth: maxDepth = thisDepth
    return maxDepth

#更新createPlot代码以得到整棵树
def plotMidText(cntrPt, parentPt, txtString):
    xMid = (parentPt[0]-cntrPt[0])/2.0 + cntrPt[0]
    yMid = (parentPt[1]-cntrPt[1])/2.0 + cntrPt[1]
    createPlot.ax1.text(xMid, yMid, txtString, va="center", ha="center", rotation=30)

def plotTree(myTree, parentPt, nodeTxt):#if the first key tells you what feat was split on
    numLeafs = getNumLeafs(myTree)  #this determines the x width of this tree
    depth = getTreeDepth(myTree)
    firstStr = myTree.keys()[0]     #the text label for this node should be this
    cntrPt = (plotTree.xOff + (1.0 + float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff)
    plotMidText(cntrPt, parentPt, nodeTxt)
    plotNode(firstStr, cntrPt, parentPt, decisionNode)
    secondDict = myTree[firstStr]
    plotTree.yOff = plotTree.yOff - 1.0/plotTree.totalD
    for key in secondDict.keys():
        if type(secondDict[key]).__name__=='dict':#test to see if the nodes are dictonaires, if not they are leaf nodes
            plotTree(secondDict[key],cntrPt,str(key))        #recursion
        else:   #it's a leaf node print the leaf node
            plotTree.xOff = plotTree.xOff + 1.0/plotTree.totalW
            plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)
            plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))
    plotTree.yOff = plotTree.yOff + 1.0/plotTree.totalD
#if you do get a dictonary you know it's a tree, and the first element will be another dict

def createPlot(inTree):
    fig = plt.figure(1, facecolor='white')
    fig.clf()
    axprops = dict(xticks=[], yticks=[])
    createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)    #no ticks
    #createPlot.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses
    plotTree.totalW = float(getNumLeafs(inTree))
    plotTree.totalD = float(getTreeDepth(inTree))
    plotTree.xOff = -0.5/plotTree.totalW; plotTree.yOff = 1.0;
    plotTree(inTree, (0.5,1.0), '')
    plt.show()

当中index方法为查找当前列表中第一个匹配firstStr的元素 返回的为索引。

4:使用决策树预測隐形眼镜类型

注明:1:本笔记来源于书籍<机器学习实战>

2:kNN.py文件及笔记所用数据在这下载(http://download.csdn.net/detail/lu597203933/7660737).

————————————————————————————————————————————————————————
随机森林
兴许我们添加了随机森林的部分
原因: 决策树对于训练样本具有较好的泛化能力,可是对于測试集未必有较好的泛化能力,亦就可以能发生过拟合现象。

我们能够採用两种方法解决。一种是剪枝。第二种是随机森林,实际中后者更简单,更方便。所以这里介绍随机森林。
bagging方法: 介绍随机森林前。我们须要介绍bagging方法,bagging是bootstrap aggregative的意思,bootstraping的思想是依靠你自己的资源。称为自助法,它是一种有放回的抽样方法;隐喻为不须要外界的帮助。仅依靠自身的力量让自己变得更好——pull up by your own bootstraps!
下面Bagging策略:


watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTHU1OTcyMDM5MzM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >
注意:重採样为有放回的取n个样本。
随机森林就是对决策树进行bagging方法就能够了。当然此处採用的算法能够是C4.5或者ID3或者CART,下面以CART进行描写叙述:


參考文献:http://www.julyedu.com/video/play/id/17
作者:小村长  出处:http://blog.csdn.net/lu597203933 欢迎转载或分享。但一定要注明文章来源。

(新浪微博:小村庄zack, 欢迎交流!)
时间: 2024-08-02 04:28:28

机器学习实践笔记3(树和随机森林)的相关文章

机器学习知识点查漏补缺(随机森林和extraTrees)

随机森林 对数据样本及特征随机抽取,进行多个决策树训练,防止过拟合,提高泛化能力 一般随机森林的特点: 1.有放回抽样(所以生成每棵树的时候,实际数据集会有重复), 2.以最优划分分裂 Given a standard training set D of size n, bagging generates m new training sets D_i, each of size n′, by sampling from D uniformly and with replacement. Thi

web安全之机器学习入门——3.2 决策树与随机森林算法

目录 简介 决策树简单用法 决策树检测P0P3爆破 决策树检测FTP爆破 随机森林检测FTP爆破 简介 决策树和随机森林算法是最常见的分类算法: 决策树,判断的逻辑很多时候和人的思维非常接近. 随机森林算法,利用多棵决策树对样本进行训练并预测的一种分类器,并且其输出的类别是由个别决策树输出的类别的众数决定. 决策树简单用法 使用sklearn自带的iris数据集 # -*- coding: utf-8 -*- from sklearn.datasets import load_iris from

2机器学习实践笔记(k-最近邻)

1:算法是简单的叙述说明 由于训练数据样本和标签,为测试数据的示例,从最近的距离k训练样本,此k练样本中所属类别最多的类即为该測试样本的预測标签. 简称kNN.通常k是不大于20的整数,这里的距离通常是欧式距离. 2:python代码实现 创建一个kNN.py文件,将核心代码放在里面了. (1)   创建数据 #创造数据集 def createDataSet(): group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]]) labels =

机器学习(五)-决策树和随机森林

这节课终于不是那么迷糊了,如果100分满分的话,听懂程度有70分了,初学者就是这么容易满足. :| 老师说这是这20次课里最简单的一次...oh...no. 不废话了,接着记笔记吧. CART:classsification and regression tree 三种决策树:ID3,C4.5,CART 树是最重要的数据结构. 决策树示意图: 决策树最重要的知识点: 决策树学习采用的是自顶向下的递归方法,其基本思想是以信息熵为度量构造一棵熵值下降最快的树,到叶子节点处的熵值为零.此时每个叶节点中

R语言︱机器学习模型评估方案(以随机森林算法为例)

R语言︱机器学习模型评估方案(以随机森林算法为例) 笔者寄语:本文中大多内容来自<数据挖掘之道>,本文为读书笔记.在刚刚接触机器学习的时候,觉得在监督学习之后,做一个混淆矩阵就已经足够,但是完整的机器学习解决方案并不会如此草率.需要完整的评价模型的方式. 常见的应用在监督学习算法中的是计算平均绝对误差(MAE).平均平方差(MSE).标准平均方差(NMSE)和均值等,这些指标计算简单.容易理解:而稍微复杂的情况下,更多地考虑的是一些高大上的指标,信息熵.复杂度和基尼值等等. 本篇可以用于情感挖

机器学习:随机森林

? ? 引言 ? ? 随机森林在机器学习实战中没有讲到,我是从伯克利大学的一个叫breiman的主页中看到相关的资料,这个breiman好像是随机森林算法的提出者,网址如下 ? ? http://www.stat.berkeley.edu/~breiman/RandomForests/cc_home.htm ? ? 随机森林算法简介 ? ? 随机森林说白了就是很多个决策树组成在一起,就形成了森林,关键在于如何创建森林里的每一棵树,随机森林用到的方法bootstrap法,通俗的讲就是有放回的抽取样

机器学习——随机森林算法及原理

1. 随机森林使用背景 1.1 随机森林定义 随机森林是一种比较新的机器学习模型.经典的机器学习模型是神经网络,有半个多世纪的历史了.神经网络预测精确,但是计算量很大.上世纪八十年代Breiman等人发明分类树的算法(Breiman et al. 1984),通过反复二分数据进行分类或回归,计算量大大降低.2001年Breiman把分类树组合成随机森林(Breiman 2001a),即在变量(列)的使用和数据(行)的使用上进行随机化,生成很多分类树,再汇总分类树的结果.随机森林在运算量没有显著提

R语言︱决策树族——随机森林算法

笔者寄语:有一篇<有监督学习选择深度学习还是随机森林或支持向量机?>(作者Bio:SebastianRaschka)中提到,在日常机器学习工作或学习中,当我们遇到有监督学习相关问题时,不妨考虑下先用简单的假设空间(简单模型集合),例如线性模型逻辑回归.若效果不好,也即并没达到你的预期或评判效果基准时,再进行下换其他更复杂模型来实验. ---------------------------------------------- 一.随机森林理论介绍 1.1 优缺点 优点. (1)不必担心过度拟合

随机森林和GBDT的学习

参考文献:http://www.zilhua.com/629.html http://www.tuicool.com/articles/JvMJve http://blog.sina.com.cn/s/blog_573085f70101ivj5.html 我的数据挖掘算法:https://github.com/linyiqun/DataMiningAlgorithm我的算法库:https://github.com/linyiqun/lyq-algorithms-lib 前言 提到森林,就不得不联