本文已参与「新人创造礼」活动,一同开启创造之路。


以下内容来源互联网与书籍。


1.决议计划树算法原理

决议计划树的根本原理是:关于一个数据集DD,其根本的格局是由多个未知相关的多个特征共同决定一个输出。假如是分类问题,那么最终的输出是类别;而假如是回归问题,最终输出的是一个回归值。而在决议计划树的思维中,便是要对多个未知相关的特征挑选出最合适的一个特征(比方运用信息增益等等),来对数据集DD进行区分,区分为多个子数据集。然后,关于这些相同的感觉信息增益进一步区分子数据集,这是一个迭代的进程,最终得到一整个的决议计划树结构来处理当时特征输出哪一类或许是输出哪一个特征值。

1.1 信息增益

一条信息的信息量和其不确定性有直接的联系。一个问题的不确定性越大,那么要搞清楚这个问题,需求了解的信息就越多,其信息熵就越大。信息熵的核算公式为:

H(X)=−∑x∈XP(x)log⁡2P(x)H(X) = -\sum_{x \in X}P(x)\log_{2}P(x)

其间:P(x)P(x)表明事件x呈现的概率

而当构建一个决议计划树时,咱们需求遍历一切的特征,假如挑选特征前后信息熵的改变起伏最大的那一个特征AA,来优选作为数据集区分的依据。其间,这儿涉及到的信息熵改变起伏也便是信息增益。其表明是区分数据前与依据特征AA区分数据后,数据集的信息熵的改变起伏。将信息增益界说为:g(D,A)g(D,A)

表达式为:

g(D,A)=H(D)−H(D∣A)g(D,A) = H(D)-H(D|A)

其间:H(D)H(D)表明经历熵,也便是数据集D自身的不确定性;而H(D∣A)H(D|A)表明条件熵,是在A条件下调集D的不确定性。

而信息增益比能够表明为:

gR(D,A)=g(D,A)H(D∣A)g_{R}(D,A) = \frac{g(D,A)}{H(D|A)}

这儿,我了解的是信息增益与练习集D关于特征A的信息熵。

1.1.1 信息增益核算比方

下面以一个比方阐明详细的核算办法,比方一个盒子中有红白黑蓝4中颜色的球共16个。其间红球2个,白球2个,黑球4个,蓝球8个。其间红球黑球体积单位为1,而白球蓝球体积单位为2。红球白球黑球质量单位为1,而蓝球质量单位为2。

在决议计划树的思维里,咱们要对这些球做一个分类,来更好猜测。分类就需求挑选一个特征对数据集进行区分,而挑选的特征有颜色,质量,体积,咱们需求对这些特征别离核算其信息增益,来挑选使得数据集愈加有序。

  1. 首要,核算基础的信息熵

也便是区分数据集前的信息熵。红白黑蓝球呈现的概率别离是:2/16、2/16、4/16、8/16。所以,区分前的信息熵核算为:

H(Dbase)=−(216log⁡2216+216log⁡2216+416log⁡2416+816log⁡2816)=1.75H(D_{base}) = -(\frac{2}{16}\log_{2}\frac{2}{16}+\frac{2}{16}\log_{2}\frac{2}{16}+\frac{4}{16}\log_{2}\frac{4}{16}+\frac{8}{16}\log_{2}\frac{8}{16})=1.75
  1. 核算体积特征的信息增益

现在挑选体积这个特征对数据集进行区分,这时就会区分出两个数据集。由于红球黑球的体积单位是1,而白球蓝球的体积单位是2。关于榜首个子数据集,红球黑球别离是2个与4个,概率别离为26\frac{2}{6}46\frac{4}{6},所以其信息熵为:

H(D1sub1)=−(26log⁡226+46log⁡246)=0.918296H(D1_{sub1}) = -(\frac{2}{6}\log_{2}\frac{2}{6}+\frac{4}{6}\log_{2}\frac{4}{6})=0.918296

关于第二字数据集白球黑球别离是2个与8个,其概率别离为210\frac{2}{10}810\frac{8}{10},所以其信息熵为:

H(D1sub2)=−(210log⁡2210+810log⁡2810)=0.721928H(D1_{sub2}) = -(\frac{2}{10}\log_{2}\frac{2}{10}+\frac{8}{10}\log_{2}\frac{8}{10})=0.721928

所以,运用了体积这个特征区分数据集后,其信息熵为:H(D1)=H(D1sub1)+H(D1sub2)H(D1) = H(D1_{sub1}) +H(D1_{sub2}),其信息增益既为:

H(Dbase)−H(D1)=1.75−1.640224=0.109776H(D_{base}) – H(D1) = 1.75-1.640224=0.109776
  1. 核算质量特征的信息增益

相同的,关于质量这个特征相同能够对数据进行区分红两个子数据集,红白黑球的质量都是1个单位;而蓝球的质量单位是2。针对榜首个子数据集,红白黑球呈现的概率别离是2/8、2/8/、4/8,所以其信息熵为:

H(D2sub1)=−(28log⁡228+28log⁡228+48log⁡248)=1.5H(D2_{sub1}) = -(\frac{2}{8}\log_{2}\frac{2}{8}+\frac{2}{8}\log_{2}\frac{2}{8} +\frac{4}{8}\log_{2}\frac{4}{8})=1.5

而第二个子数据会集只有蓝球,其概率为1,所以其信息熵为0。所以用质量区分的信息增益为:

H(Dbase)−H(D2)=1.75−1.5=0.25H(D_{base}) – H(D2) = 1.75-1.5=0.25
  1. 挑选最高的信息增益

由于运用质量区分数据集比运用体积区分数据集得到了更高的信息增益,所以优先挑选质量这个特征区分数据集。

1.1.2 信息增益代码完成

  1. 创立数据集,核算经历熵的代码如下:
from math import log
"""
函数阐明:创立测验数据集
Parameters:无
Returns:
    dataSet:数据集
    labels:分类特点
Modify:
    2018-03-12
"""
def creatDataSet():
    # 数据集
    dataSet=[[0, 0, 0, 0, 'no'],
            [0, 0, 0, 1, 'no'],
            [0, 1, 0, 1, 'yes'],
            [0, 1, 1, 0, 'yes'],
            [0, 0, 0, 0, 'no'],
            [1, 0, 0, 0, 'no'],
            [1, 0, 0, 1, 'no'],
            [1, 1, 1, 1, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [2, 0, 1, 2, 'yes'],
            [2, 0, 1, 1, 'yes'],
            [2, 1, 0, 1, 'yes'],
            [2, 1, 0, 2, 'yes'],
            [2, 0, 0, 0, 'no']]
    #分类特点
    labels=['年纪','有作业','有自己的房子','信贷状况']
    #回来数据集和分类特点
    return dataSet,labels
"""
函数阐明:核算给定数据集的经历熵(香农熵)
Parameters:
    dataSet:数据集
Returns:
    shannonEnt:经历熵
Modify:
    2018-03-12
"""
def calcShannonEnt(dataSet):
    #回来数据集行数
    numEntries=len(dataSet)
    #保存每个标签(label)呈现次数的字典
    labelCounts={}
    #对每组特征向量进行核算
    for featVec in dataSet:
        currentLabel=featVec[-1]                     #提取标签信息
        if currentLabel not in labelCounts.keys():   #假如标签没有放入核算次数的字典,增加进去
            labelCounts[currentLabel]=0
        labelCounts[currentLabel]+=1                 #label计数
    shannonEnt=0.0                                   #经历熵
    #核算经历熵
    for key in labelCounts:
        prob=float(labelCounts[key])/numEntries      #挑选该标签的概率
        shannonEnt-=prob*log(prob,2)                 #运用公式核算
    return shannonEnt                                #回来经历熵
#main函数
if __name__=='__main__':
    dataSet,features=creatDataSet()
    print(dataSet)
    print(calcShannonEnt(dataSet))

成果:

0个特征的增益为0.0831个特征的增益为0.3242个特征的增益为0.4203个特征的增益为0.3630个特征的增益为0.2521个特征的增益为0.9182个特征的增益为0.474
{'有自己的房子': {0: {'有作业': {0: 'no', 1: 'yes'}}, 1: 'yes'}}
  1. 运用代码核算信息增益

from math import log
"""
函数阐明:创立测验数据集
Parameters:无
Returns:
    dataSet:数据集
    labels:分类特点
Modify:
    2018-03-12
"""
def creatDataSet():
    # 数据集
    dataSet=[[0, 0, 0, 0, 'no'],
            [0, 0, 0, 1, 'no'],
            [0, 1, 0, 1, 'yes'],
            [0, 1, 1, 0, 'yes'],
            [0, 0, 0, 0, 'no'],
            [1, 0, 0, 0, 'no'],
            [1, 0, 0, 1, 'no'],
            [1, 1, 1, 1, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [2, 0, 1, 2, 'yes'],
            [2, 0, 1, 1, 'yes'],
            [2, 1, 0, 1, 'yes'],
            [2, 1, 0, 2, 'yes'],
            [2, 0, 0, 0, 'no']]
    #分类特点
    labels=['年纪','有作业','有自己的房子','信贷状况']
    #回来数据集和分类特点
    return dataSet,labels
"""
函数阐明:核算给定数据集的经历熵(香农熵)
Parameters:
    dataSet:数据集
Returns:
    shannonEnt:经历熵
Modify:
    2018-03-12
"""
def calcShannonEnt(dataSet):
    #回来数据集行数
    numEntries=len(dataSet)
    #保存每个标签(label)呈现次数的字典
    labelCounts={}
    #对每组特征向量进行核算
    for featVec in dataSet:
        currentLabel=featVec[-1]                     #提取标签信息
        if currentLabel not in labelCounts.keys():   #假如标签没有放入核算次数的字典,增加进去
            labelCounts[currentLabel]=0
        labelCounts[currentLabel]+=1                 #label计数
    shannonEnt=0.0                                   #经历熵
    #核算经历熵
    for key in labelCounts:
        prob=float(labelCounts[key])/numEntries      #挑选该标签的概率
        shannonEnt-=prob*log(prob,2)                 #运用公式核算
    return shannonEnt                                #回来经历熵
"""
函数阐明:核算给定数据集的经历熵(香农熵)
Parameters:
    dataSet:数据集
Returns:
    shannonEnt:信息增益最大特征的索引值
Modify:
    2018-03-12
"""
def chooseBestFeatureToSplit(dataSet):
    #特征数量
    numFeatures = len(dataSet[0]) - 1
    #计数数据集的香农熵
    baseEntropy = calcShannonEnt(dataSet)
    #信息增益
    bestInfoGain = 0.0
    #最优特征的索引值
    bestFeature = -1
    #遍历一切特征
    for i in range(numFeatures):
        # 获取dataSet的第i个一切特征
        featList = [example[i] for example in dataSet]
        #创立set调集{},元素不行重复
        uniqueVals = set(featList)
        #经历条件熵
        newEntropy = 0.0
        #核算信息增益
        for value in uniqueVals:
            #subDataSet区分后的子集
            subDataSet = splitDataSet(dataSet, i, value)
            #核算子集的概率
            prob = len(subDataSet) / float(len(dataSet))
            #依据公式核算经历条件熵
            newEntropy += prob * calcShannonEnt((subDataSet))
        #信息增益
        infoGain = baseEntropy - newEntropy
        #打印每个特征的信息增益
        print("第%d个特征的增益为%.3f" % (i, infoGain))
        #核算信息增益
        if (infoGain > bestInfoGain):
            #更新信息增益,找到最大的信息增益
            bestInfoGain = infoGain
            #记载信息增益最大的特征的索引值
            bestFeature = i
            #回来信息增益最大特征的索引值
    return bestFeature
"""
函数阐明:依照给定特征区分数据集
Parameters:
    dataSet:待区分的数据集
    axis:区分数据集的特征
    value:需求回来的特征的值
Returns:
    shannonEnt:经历熵
Modify:
    2018-03-12
"""
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
#main函数
if __name__=='__main__':
    dataSet,features=creatDataSet()
    # print(dataSet)
    # print(calcShannonEnt(dataSet))
    print("最优索引值:"+str(chooseBestFeatureToSplit(dataSet)))

成果:

0个特征的增益为0.0831个特征的增益为0.3242个特征的增益为0.4203个特征的增益为0.363
最优索引值:2

1.2 决议计划树的构建

决议计划树的创立根本上分为以下几步: 1)核算数据集区分前的信息熵 2)遍历所以未作为区分条件的特征,别离核算依据每个特征区分数据集后的信息熵 3)挑选想你想增益最大的特征,并运用这个特征作为数据区分节点来区分数据 4)递归处理被区分后的所以子数据集,从未被挑选的特征里持续挑选最优数据区分特征来区分子数据集

其间:递归结束的终止条件有两个: 一是所以的特征都用完了,没有新的特征能够用来进一步区分数据集。 二是区分后的信息增益满足小了。

在后面的内容会提及到,sklearn中供给了许多的参数来挑选数据集的样本大小后者是决议计划树的叶子节点的大小又或许是决议计划树的深度等等。不过这儿首要是用代码直观了解,而不是简单调用。

其间,运用信息增益作为特征挑选目标的决议计划树构建算法称为ID3算法;而运用信息增益比作为特征挑选目标的决议计划树构建算法称为C4.5算法

1.2.1 ID3、C4.5、CART算法

这三个是十分闻名的决议计划树算法。简单粗暴来说,ID3 运用信息增益作为挑选特征的准则;C4.5 运用信息增益比作为挑选特征的准则;CART 运用 Gini 指数作为挑选特征的准则。

  1. ID3算法

熵表明的是数据中包括的信息量大小。熵越小,数据的纯度越高,也便是说数据越趋于共同,这是咱们期望的区分之后每个子节点的姿态。

信息增益 = 区分前熵 – 区分后熵。信息增益越大,则意味着运用特点 a 来进行区分所取得的 “纯度进步” 越大 **。也便是说,用特点 a 来区分练习集,得到的成果中纯度比较高。

ID3 只是适用于二分类问题。ID3 只是能够处理离散特点。

  1. C4.5算法

C4.5 克服了 ID3 只是能够处理离散特点的问题,以及信息增益倾向挑选取值较多特征的问题,运用信息增益比来挑选特征。信息增益比 = 信息增益 / 区分前熵 挑选信息增益比最大的作为最优特征。

C4.5 处理接连特征是先将特征取值排序,以接连两个值中心值作为区分规范。测验每一种区分,并核算修正后的信息增益,挑选信息增益最大的分裂点作为该特点的分裂点。

  1. CART算法

CART 与 ID3,C4.5 不同之处在于 CART 生成的树有必要是二叉树。也便是说,不论是回归仍是分类问题,不论特征是离散的仍是接连的,不论特点取值有多个仍是两个,内部节点只能依据特点值进行二分。

CART 的全称是分类与回归树。从这个名字中就应该知道,CART 既能够用于分类问题,也能够用于回归问题。

回归树中,运用平方差错最小化准则来挑选特征并进行区分。每一个叶子节点给出的猜测值,是区分到该叶子节点的一切样本目标值的均值,这样只是在给定区分的状况下最小化了平方差错。

要确定最优化分,还需求遍历一切特点,以及其一切的取值来别离测验区分并核算在此种区分状况下的最小平方差错,选取最小的作为此次区分的依据。由于回归树生成运用平方差错最小化准则,所以又叫做最小二乘回归树。

分类树种,运用 Gini 指数最小化准则来挑选特征并进行区分;

Gini 指数表明调集的不确定性,或许是不纯度。基尼指数越大,调集不确定性越高,不纯度也越大。这一点和熵类似。另一种了解基尼指数的思路是,基尼指数是为了最小化误分类的概率。

信息增益 vs 信息增益比

之所以引入了信息增益比,是由于信息增益的一个缺陷。那便是:信息增益总是倾向于挑选取值较多的特点。信息增益比在此基础上增加了一个罚项,处理了这个问题。

Gini 指数 vs 熵

已然这两个都能够表明数据的不确定性,不纯度。那么这两个有什么区别那?

  • Gini 指数的核算不需求对数运算,愈加高效;
  • Gini 指数更倾向于接连特点,熵更倾向于离散特点。

1.2.2 ID3算法代码完成

编写ID3算法的代码

from math import log
import operator
"""
函数阐明:核算给定数据集的经历熵(香农熵)
Parameters:
    dataSet:数据集
Returns:
    shannonEnt:经历熵
Modify:
    2018-03-12
"""
def calcShannonEnt(dataSet):
    #回来数据集行数
    numEntries=len(dataSet)
    #保存每个标签(label)呈现次数的字典
    labelCounts={}
    #对每组特征向量进行核算
    for featVec in dataSet:
        currentLabel=featVec[-1]                     #提取标签信息
        if currentLabel not in labelCounts.keys():   #假如标签没有放入核算次数的字典,增加进去
            labelCounts[currentLabel]=0
        labelCounts[currentLabel]+=1                 #label计数
    shannonEnt=0.0                                   #经历熵
    #核算经历熵
    for key in labelCounts:
        prob=float(labelCounts[key])/numEntries      #挑选该标签的概率
        shannonEnt-=prob*log(prob,2)                 #运用公式核算
    return shannonEnt                                #回来经历熵
"""
函数阐明:创立测验数据集
Parameters:无
Returns:
    dataSet:数据集
    labels:分类特点
Modify:
    2018-03-13
"""
def createDataSet():
    # 数据集
    dataSet=[[0, 0, 0, 0, 'no'],
            [0, 0, 0, 1, 'no'],
            [0, 1, 0, 1, 'yes'],
            [0, 1, 1, 0, 'yes'],
            [0, 0, 0, 0, 'no'],
            [1, 0, 0, 0, 'no'],
            [1, 0, 0, 1, 'no'],
            [1, 1, 1, 1, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [2, 0, 1, 2, 'yes'],
            [2, 0, 1, 1, 'yes'],
            [2, 1, 0, 1, 'yes'],
            [2, 1, 0, 2, 'yes'],
            [2, 0, 0, 0, 'no']]
    #分类特点
    labels=['年纪','有作业','有自己的房子','信贷状况']
    #回来数据集和分类特点
    return dataSet,labels
"""
函数阐明:依照给定特征区分数据集
Parameters:
    dataSet:待区分的数据集
    axis:区分数据集的特征
    value:需求回来的特征值
Returns:
    无
Modify:
    2018-03-13
"""
def splitDataSet(dataSet,axis,value):
    #创立回来的数据集列表
    retDataSet=[]
    #遍历数据集
    for featVec in dataSet:
        if featVec[axis]==value:
            #去掉axis特征
            reduceFeatVec=featVec[:axis]
            #将契合条件的增加到回来的数据集
            reduceFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reduceFeatVec)
    #回来区分后的数据集
    return retDataSet
"""
函数阐明:核算给定数据集的经历熵(香农熵)
Parameters:
    dataSet:数据集
Returns:
    shannonEnt:信息增益最大特征的索引值
Modify:
    2018-03-13
"""
def chooseBestFeatureToSplit(dataSet):
    #特征数量
    numFeatures = len(dataSet[0]) - 1
    #计数数据集的香农熵
    baseEntropy = calcShannonEnt(dataSet)
    #信息增益
    bestInfoGain = 0.0
    #最优特征的索引值
    bestFeature = -1
    #遍历一切特征
    for i in range(numFeatures):
        # 获取dataSet的第i个一切特征
        featList = [example[i] for example in dataSet]
        #创立set调集{},元素不行重复
        uniqueVals = set(featList)
        #经历条件熵
        newEntropy = 0.0
        #核算信息增益
        for value in uniqueVals:
            #subDataSet区分后的子集
            subDataSet = splitDataSet(dataSet, i, value)
            #核算子集的概率
            prob = len(subDataSet) / float(len(dataSet))
            #依据公式核算经历条件熵
            newEntropy += prob * calcShannonEnt((subDataSet))
        #信息增益
        infoGain = baseEntropy - newEntropy
        #打印每个特征的信息增益
        print("第%d个特征的增益为%.3f" % (i, infoGain))
        #核算信息增益
        if (infoGain > bestInfoGain):
            #更新信息增益,找到最大的信息增益
            bestInfoGain = infoGain
            #记载信息增益最大的特征的索引值
            bestFeature = i
            #回来信息增益最大特征的索引值
    return bestFeature
"""
函数阐明:核算classList中呈现次数最多的元素(类标签)
Parameters:
    classList:类标签列表
Returns:
    sortedClassCount[0][0]:呈现次数最多的元素(类标签)
Modify:
    2018-03-13
"""
def majorityCnt(classList):
    classCount={}
    #核算classList中每个元素呈现的次数
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote]=0
            classCount[vote]+=1
        #依据字典的值降序摆放
        sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
        return sortedClassCount[0][0]
"""
函数阐明:创立决议计划树
Parameters:
    dataSet:练习数据集
    labels:分类特点标签
    featLabels:存储挑选的最优特征标签
Returns:
    myTree:决议计划树
Modify:
    2018-03-13
"""
def createTree(dataSet,labels,featLabels):
    #取分类标签(是否放贷:yes or no)
    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]
    featLabels.append(bestFeatLabel)
    #依据最优特征的标签生成树
    myTree={bestFeatLabel:{}}
    #删去现已运用的特征标签
    del(labels[bestFeat])
    #得到练习会集一切最优特征的特点值
    featValues=[example[bestFeat] for example in dataSet]
    #去掉重复的特点值
    uniqueVls=set(featValues)
    #遍历特征,创立决议计划树
    for value in uniqueVls:
        myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),
                                               labels,featLabels)
    return myTree
if __name__=='__main__':
    dataSet,labels=createDataSet()
    featLabels=[]
    myTree=createTree(dataSet,labels,featLabels)
    print(myTree)

成果:

0个特征的增益为0.0831个特征的增益为0.3242个特征的增益为0.4203个特征的增益为0.3630个特征的增益为0.2521个特征的增益为0.9182个特征的增益为0.474
{'有自己的房子': {0: {'有作业': {0: 'no', 1: 'yes'}}, 1: 'yes'}}

1.3 决议计划树剪枝处理

决议计划树生成算法递归的发生决议计划树,直到不能持续下去为止,这样发生的树往往对练习数据的分类很准确,但对未知测验数据的分类缺没有那么精确,即会呈现过拟合现象。过拟合发生的原因在于在学习时过多的考虑如何进步对练习数据的正确分类,然后构建出过于杂乱的决议计划树,处理办法是考虑决议计划树的杂乱度,对现已生成的树进行简化。

1.3.1 前剪枝

前剪枝是在结构决议计划树的一同进行剪枝。

1)运用阈值进行限定 在决议计划树的构建进程中,信息熵现已无法进一步的下降,现已低过所设置的阈值,中止分支

2)约束叶子节点样本个数 当样本个数小于必定的阈值时,不再持续创立分支也能够进行剪枝

sklearn中进步了许多前剪枝的参数,能够自在设置,或许所以GridSearchCV进行寻找最优参数。

1.3.2 后剪枝

后剪枝是指决议计划树结构完成后进行剪枝处理。剪枝的进程是对拥有相同的父节点的一组节点进行检查,判别假如将其兼并,信息熵的增加量是否小于某一个阈值。假如小于阈值,则这一组节点能够兼并一个节点。

可是sklearn没有供给后剪枝的办法。

1.4 决议计划数分类完成

依托练习数据结构了决议计划树之后,咱们能够将它用于实践数据的分类。在履行数据分类时,需求决议计划树以及用于结构树的标签向量。然后,程序比较测验数据与决议计划树上的数值,递归履行该进程直到进入叶子结点;最终将测验数据界说为叶子结点所属的类型。在构建决议计划树的代码,能够看到,有个featLabels参数。它是用来干什么的?它便是用来记载各个分类结点的,在用决议计划树做猜测的时分,咱们按次序输入需求的分类结点的特点值即可。举个比方,比方我用上述现已练习好的决议计划树做分类,那么我只需求供给这个人是否有房子,是否有作业这两个信息即可,无需供给冗余的信息。

代码如下:

from math import log
import operator
"""
函数阐明:核算给定数据集的经历熵(香农熵)
Parameters:
    dataSet:数据集
Returns:
    shannonEnt:经历熵
Modify:
    2018-03-12
"""
def calcShannonEnt(dataSet):
    #回来数据集行数
    numEntries=len(dataSet)
    #保存每个标签(label)呈现次数的字典
    labelCounts={}
    #对每组特征向量进行核算
    for featVec in dataSet:
        currentLabel=featVec[-1]                     #提取标签信息
        if currentLabel not in labelCounts.keys():   #假如标签没有放入核算次数的字典,增加进去
            labelCounts[currentLabel]=0
        labelCounts[currentLabel]+=1                 #label计数
    shannonEnt=0.0                                   #经历熵
    #核算经历熵
    for key in labelCounts:
        prob=float(labelCounts[key])/numEntries      #挑选该标签的概率
        shannonEnt-=prob*log(prob,2)                 #运用公式核算
    return shannonEnt                                #回来经历熵
"""
函数阐明:创立测验数据集
Parameters:无
Returns:
    dataSet:数据集
    labels:分类特点
Modify:
    2018-03-13
"""
def createDataSet():
    # 数据集
    dataSet=[[0, 0, 0, 0, 'no'],
            [0, 0, 0, 1, 'no'],
            [0, 1, 0, 1, 'yes'],
            [0, 1, 1, 0, 'yes'],
            [0, 0, 0, 0, 'no'],
            [1, 0, 0, 0, 'no'],
            [1, 0, 0, 1, 'no'],
            [1, 1, 1, 1, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [2, 0, 1, 2, 'yes'],
            [2, 0, 1, 1, 'yes'],
            [2, 1, 0, 1, 'yes'],
            [2, 1, 0, 2, 'yes'],
            [2, 0, 0, 0, 'no']]
    #分类特点
    labels=['年纪','有作业','有自己的房子','信贷状况']
    #回来数据集和分类特点
    return dataSet,labels
"""
函数阐明:依照给定特征区分数据集
Parameters:
    dataSet:待区分的数据集
    axis:区分数据集的特征
    value:需求回来的特征值
Returns:
    无
Modify:
    2018-03-13
"""
def splitDataSet(dataSet,axis,value):
    #创立回来的数据集列表
    retDataSet=[]
    #遍历数据集
    for featVec in dataSet:
        if featVec[axis]==value:
            #去掉axis特征
            reduceFeatVec=featVec[:axis]
            #将契合条件的增加到回来的数据集
            reduceFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reduceFeatVec)
    #回来区分后的数据集
    return retDataSet
"""
函数阐明:核算给定数据集的经历熵(香农熵)
Parameters:
    dataSet:数据集
Returns:
    shannonEnt:信息增益最大特征的索引值
Modify:
    2018-03-13
"""
def chooseBestFeatureToSplit(dataSet):
    #特征数量
    numFeatures = len(dataSet[0]) - 1
    #计数数据集的香农熵
    baseEntropy = calcShannonEnt(dataSet)
    #信息增益
    bestInfoGain = 0.0
    #最优特征的索引值
    bestFeature = -1
    #遍历一切特征
    for i in range(numFeatures):
        # 获取dataSet的第i个一切特征
        featList = [example[i] for example in dataSet]
        #创立set调集{},元素不行重复
        uniqueVals = set(featList)
        #经历条件熵
        newEntropy = 0.0
        #核算信息增益
        for value in uniqueVals:
            #subDataSet区分后的子集
            subDataSet = splitDataSet(dataSet, i, value)
            #核算子集的概率
            prob = len(subDataSet) / float(len(dataSet))
            #依据公式核算经历条件熵
            newEntropy += prob * calcShannonEnt((subDataSet))
        #信息增益
        infoGain = baseEntropy - newEntropy
        #打印每个特征的信息增益
        print("第%d个特征的增益为%.3f" % (i, infoGain))
        #核算信息增益
        if (infoGain > bestInfoGain):
            #更新信息增益,找到最大的信息增益
            bestInfoGain = infoGain
            #记载信息增益最大的特征的索引值
            bestFeature = i
            #回来信息增益最大特征的索引值
    return bestFeature
"""
函数阐明:核算classList中呈现次数最多的元素(类标签)
Parameters:
    classList:类标签列表
Returns:
    sortedClassCount[0][0]:呈现次数最多的元素(类标签)
Modify:
    2018-03-13
"""
def majorityCnt(classList):
    classCount={}
    #核算classList中每个元素呈现的次数
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote]=0
            classCount[vote]+=1
        #依据字典的值降序摆放
        sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
        return sortedClassCount[0][0]
"""
函数阐明:创立决议计划树
Parameters:
    dataSet:练习数据集
    labels:分类特点标签
    featLabels:存储挑选的最优特征标签
Returns:
    myTree:决议计划树
Modify:
    2018-03-13
"""
def createTree(dataSet,labels,featLabels):
    #取分类标签(是否放贷:yes or no)
    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]
    featLabels.append(bestFeatLabel)
    #依据最优特征的标签生成树
    myTree={bestFeatLabel:{}}
    #删去现已运用的特征标签
    del(labels[bestFeat])
    #得到练习会集一切最优特征的特点值
    featValues=[example[bestFeat] for example in dataSet]
    #去掉重复的特点值
    uniqueVls=set(featValues)
    #遍历特征,创立决议计划树
    for value in uniqueVls:
        myTree[bestFeatLabel][value]=createTree(splitDataSet(dataSet,bestFeat,value),
                                               labels,featLabels)
    return myTree
"""
运用决议计划树进行分类
Parameters:
    inputTree;现已生成的决议计划树
    featLabels:存储挑选的最优特征标签
    testVec:测验数据列表,次序对应最优特征标签
Returns:
    classLabel:分类成果
Modify:2018-03-13
"""
def classify(inputTree,featLabels,testVec):
    #获取决议计划树节点
    firstStr=next(iter(inputTree))
    #下一个字典
    secondDict=inputTree[firstStr]
    featIndex=featLabels.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
if __name__=='__main__':
    dataSet,labels=createDataSet()
    featLabels=[]
    myTree=createTree(dataSet,labels,featLabels)
    #测验数据
    testVec=[0,1]
    result=classify(myTree,featLabels,testVec)
    if result=='yes':
        print('放贷')
    if result=='no':
        print('不放贷')

成果:

0个特征的增益为0.0831个特征的增益为0.3242个特征的增益为0.4203个特征的增益为0.3630个特征的增益为0.2521个特征的增益为0.9182个特征的增益为0.474
放贷

1.5 决议计划树的加载与存储

1.5.1 决议计划树存储

结构决议计划树是很耗时的使命,即便处理很小的数据集,如前面的样本数据,也要花费几秒的时刻,假如数据集很大,将会耗费许多核算时刻。然而用创立好的决议计划树处理分类问题,则能够很快完成。因而,为了节省核算时刻,最好能够在每次履行分类时调用现已结构好的决议计划树。为了处理这个问题,需求运用Python模块pickle序列化目标。序列化目标能够在磁盘上保存目标,并在需求的时分读取出来。

假定咱们现已得到决议计划树 {'有自己的房子': {0: {'有作业': {0: 'no', 1: 'yes'}}, 1: 'yes'}} 运用pickle.dump存储决议计划树。

import pickle
"""
函数阐明:存储决议计划树
Parameters:
    inputTree:现已生成的决议计划树
    filename:决议计划树的存储文件名
Returns:
    无
Modify:
    2018-03-13
"""
def storeTree(inputTree,filename):
    with open(filename,'wb') as fw:
        pickle.dump(inputTree,fw)
if __name__=='__main__':
    myTree={'有自己的房子':{0:{'有作业':{0:'no',1:'yes'}},1:'yes'}}
    storeTree(myTree,'classifierStorage.txt')

运转代码,在该Python文件的相同目录下,会生成一个名为classifierStorage.txt的txt文件,这个文件二进制存储着咱们的决议计划树。

1.5.2 决议计划树的加载

很简单运用pickle.load进行载入即可,编写代码如下:

import pickle
"""
函数阐明:读取决议计划树
Parameters:
    filename:决议计划树的存储文件名
Returns:
    pickle.load(fr):决议计划树字典
Modify:
    2018-03-13
"""
def grabTree(filename):
    fr = open(filename, 'rb')
    return pickle.load(fr)
if __name__ == '__main__':
    myTree = grabTree('classifierStorage.txt')
    print(myTree)

经过以上的代码完成应该能比较明晰的了处理议计划树的详细进程。可是一般运用的时分直接调用sklearn完成的东西包即可,不行能自己从头能够写一个决议计划树算法去运用。所以,下面内容会介绍sklearn的决议计划树运用。

2. 决议计划树算法运用

在sklearn中sklearn.tree,供给了决议计划树运用的两个接口,别离用来处理分类问题与回归问题DecisionTreeClassifier,DecisionTreeRegressor

下面对DecisionTreeClassifier函数进行简单介绍:

class sklearn.tree.DecisionTreeClassifier(
	criterion=’gini’, 
	splitter=’best’, 
	max_depth=None, 
	min_samples_split=2, 
	min_samples_leaf=1, 
	min_weight_fraction_leaf=0.0, 
	max_features=None, 
	random_state=None, 
	max_leaf_nodes=None, 
	min_impurity_decrease=0.0, 
	min_impurity_split=None, 
	class_weight=None, 
	presort=False)[source]

参数阐明如下: criterion:特征挑选规范,可选参数,默许是gini,能够设置为entropy。gini是基尼不纯度,是将来自调集的某种成果随机应用于某一数据项的预期差错率,是一种根据核算的思维。entropy是香农熵,也便是上篇文章讲过的内容,是一种根据信息论的思维。Sklearn把gini设为默许参数,应该也是做了相应的酌量的,精度也许更高些?ID3算法运用的是entropy,CART算法运用的则是gini。

splitter:特征区分点挑选规范,可选参数,默许是best,能够设置为random。每个结点的挑选策略。best参数是依据算法挑选最佳的切分特征,例如gini、entropy。random随机的在部分区分点中找局部最优的区分点。默许的”best”合适样本量不大的时分,而假如样本数据量十分大,此时决议计划树构建引荐”random”。

max_features:区分时考虑的最大特征数,可选参数,默许是None。寻找最佳切分时考虑的最大特征数(n_features为总共的特征数),有如下6种状况: 假如max_features是整型的数,则考虑max_features个特征; 假如max_features是浮点型的数,则考虑int(max_features * n_features)个特征; 假如max_features设为auto,那么max_features = sqrt(n_features); 假如max_features设为sqrt,那么max_featrues = sqrt(n_features),跟auto一样; 假如max_features设为log2,那么max_features = log2(n_features); 假如max_features设为None,那么max_features = n_features,也便是一切特征都用。 一般来说,假如样本特征数不多,比方小于50,咱们用默许的”None”就能够了,假如特征数十分多,咱们能够灵活运用刚才描绘的其他取值来操控区分时考虑的最大特征数,以操控决议计划树的生成时刻。

max_depth:决议计划树最大深,可选参数,默许是None。这个参数是这是树的层数的。层数的概念便是,比方在借款的比方中,决议计划树的层数是2层。假如这个参数设置为None,那么决议计划树在建立子树的时分不会约束子树的深度。一般来说,数据少或许特征少的时分能够不论这个值。或许假如设置了min_samples_slipt参数,那么直到少于min_smaples_split个样本为止。假如模型样本量多,特征也多的状况下,引荐约束这个最大深度,详细的取值取决于数据的散布。常用的能够取值10-100之间。

min_samples_split:内部节点再区分所需最小样本数,可选参数,默许是2。这个值约束了子树持续区分的条件。假如min_samples_split为整数,那么在切分内部结点的时分,min_samples_split作为最小的样本数,也便是说,假如样本现已少于min_samples_split个样本,则中止持续切分。假如min_samples_split为浮点数,那么min_samples_split便是一个百分比,ceil(min_samples_split * n_samples),数是向上取整的。假如样本量不大,不需求管这个值。假如样本量数量级十分大,则引荐增大这个值。

min_weight_fraction_leaf:叶子节点最小的样本权重和,可选参数,默许是0。这个值约束了叶子节点一切样本权重和的最小值,假如小于这个值,则会和兄弟节点一同被剪枝。一般来说,假如咱们有较多样本有缺失值,或许分类树样本的散布类别偏差很大,就会引入样本权重,这时咱们就要留意这个值了。

max_leaf_nodes:最大叶子节点数,可选参数,默许是None。经过约束最大叶子节点数,能够避免过拟合。假如加了约束,算法会建立在最大叶子节点数内最优的决议计划树。假如特征不多,能够不考虑这个值,可是假如特征分红多的话,能够加以约束,详细的值能够经过交叉验证得到。

class_weight:类别权重,可选参数,默许是None,也能够字典、字典列表、balanced。指定样本各类别的的权重,首要是为了避免练习集某些类别的样本过多,导致练习的决议计划树过于倾向这些类别。类别的权重能够经过{class_label:weight}这样的格局给出,这儿能够自己指定各个样本的权重,或许用balanced,假如运用balanced,则算法会自己核算权重,样本量少的类别所对应的样本权重会高。当然,假如你的样本类别散布没有明显的偏倚,则能够不论这个参数,挑选默许的None。

random_state:可选参数,默许是None。随机数种子。假如是证书,那么random_state会作为随机数生成器的随机数种子。随机数种子,假如没有设置随机数,随机出来的数与当时体系时刻有关,每个时刻都是不同的。假如设置了随机数种子,那么相同随机数种子,不一同刻发生的随机数也是相同的。假如是RandomState instance,那么random_state是随机数生成器。假如为None,则随机数生成器运用np.random。

min_impurity_split:节点区分最小不纯度,可选参数,默许是1e-7。这是个阈值,这个值约束了决议计划树的增加,假如某节点的不纯度(基尼系数,信息增益,均方差,绝对差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。

presort:数据是否预排序,可选参数,默许为False,这个值是布尔值,默许是False不排序。一般来说,假如样本量少或许约束了一个深度很小的决议计划树,设置为true能够让区分点挑选愈加速,决议计划树建立的愈加速。假如样本量太大的话,反而没有什么好处。问题是样本量少的时分,我速度原本就不慢。所以这个值一般懒得理它就能够了。

2.1 决议计划树处理分类问题

在处理分类问题中,这儿以猜测泰坦尼克号幸存者为示例介绍。决议计划树处理分类使命的根本思维是,将运用特征对数据集区分为多个样本类,然后关于需求猜测的样本逐个解析。

首要进行导入数据

%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
data = pd.read_csv('train.csv')
data.head()
.dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; }
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th… female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S

2.1.1 数据预处理

def read_dataset(fname):
    # 指定榜首列作为行索引
    data = pd.read_csv(fname, index_col=0) 
    # 丢弃无用的数据
    data.drop(['Name', 'Ticket', 'Cabin'], axis=1, inplace=True)
    # 处理性别数据
    data['Sex'] = (data['Sex'] == 'male').astype('int')
    # 处理登船港口数据
    labels = data['Embarked'].unique().tolist()
    data['Embarked'] = data['Embarked'].apply(lambda n: labels.index(n))
    # 处理缺失数据
    data = data.fillna(0)
    return data
train = read_dataset('E:/学习/机器学习/scikit-learn机器学习/code/datasets/titanic/train.csv')
train.head(6)
.dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; }
Survived Pclass Sex Age SibSp Parch Fare Embarked
PassengerId
1 0 3 1 22.0 1 0 7.2500 0
2 1 1 0 38.0 1 0 71.2833 1
3 1 3 0 26.0 0 0 7.9250 0
4 1 1 0 35.0 1 0 53.1000 0
5 0 3 1 35.0 0 0 8.0500 0
6 0 3 1 0.0 0 0 8.4583 2
from sklearn.model_selection import train_test_split
y = train['Survived'].values
X = train.drop(['Survived'], axis=1).values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
print("X_train:{}, X_test:{}, y_train:{}, y_test:{}".format(X_train.shape, X_test.shape, y_train.shape, y_test.shape))
X_train:(712, 7), X_test:(179, 7), y_train:(712,), y_test:(179,)

2.1.2 数据拟合与猜测

from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier()
clf.fit(X_train,y_train)
train_score = clf.score(X_train,y_train)
test_score = clf.score(X_test,y_test)
print("train_score:{},test_score:{}".format(train_score,test_score))
train_score:0.9831460674157303,test_score:0.776536312849162
test = read_dataset('test.csv')
test.shape
(418, 7)
testpred = clf.predict(test)
test['Survived'] = testpred
test.head(10)
.dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; }
Pclass Sex Age SibSp Parch Fare Embarked Survived
PassengerId
892 3 1 34.5 0 0 7.8292 0 0
893 3 0 47.0 1 0 7.0000 1 0
894 2 1 62.0 0 0 9.6875 0 0
895 3 1 27.0 0 0 8.6625 1 1
896 3 0 22.0 1 1 12.2875 1 1
897 3 1 14.0 0 0 9.2250 1 0
898 3 0 30.0 0 0 7.6292 0 0
899 2 1 26.0 1 1 29.0000 1 1
900 3 0 18.0 0 0 7.2292 2 1
901 3 1 21.0 2 0 24.1500 1 0

2.1.3 决议计划树可视化

from sklearn.tree import export_graphviz
with open("titanic.dot", 'w') as f:
    f = export_graphviz(clf, out_file=f)
# 1. 在电脑上装置 graphviz
# 2. 运转 `dot -Tpng titanic.dot -o titanic.png` 
# 3. 在当时目录检查生成的决议计划树 titanic.png

然后在终端输出命令dot -Tpng titanic.dot -o titanic.png即可:

机器学习原理与实战 | 决策树与集成算法实践
ps:需求设置环境变量
机器学习原理与实战 | 决策树与集成算法实践
在“环境变量”中的“体系变量”中找到“PATH”,之后将途径C:\Anaconda\pkgs\graphviz-2.38.0-4\Library\bin增加到后面,重启Pycharm即可。

2.1.4 模型参数优化

运用GridSearchCV东西进行对参数评估

from sklearn.model_selection import GridSearchCV
thresholds = np.linspace(0, 0.005, 50)
# Set the parameters by cross-validation
param_grid = {'min_impurity_decrease': thresholds}
clf = GridSearchCV(DecisionTreeClassifier(), param_grid, cv=5, return_train_score=True)
clf.fit(X, y)
print("best param: {0}\nbest score: {1}".format(clf.best_params_, 
                                                clf.best_score_))
best param: {'min_impurity_decrease': 0.0011224489795918367}
best score: 0.8137216747222397
def plot_curve(train_sizes, cv_results, xlabel):
    train_scores_mean = cv_results['mean_train_score']
    train_scores_std = cv_results['std_train_score']
    test_scores_mean = cv_results['mean_test_score']
    test_scores_std = cv_results['std_test_score']
    plt.figure(figsize=(10, 6), dpi=144)
    plt.title('parameters turning')
    plt.grid()
    plt.xlabel(xlabel)
    plt.ylabel('score')
    plt.fill_between(train_sizes, 
                     train_scores_mean - train_scores_std,
                     train_scores_mean + train_scores_std, 
                     alpha=0.1, color="r")
    plt.fill_between(train_sizes, 
                     test_scores_mean - test_scores_std,
                     test_scores_mean + test_scores_std, 
                     alpha=0.1, color="g")
    plt.plot(train_sizes, train_scores_mean, '.--', color="r",
             label="Training score")
    plt.plot(train_sizes, test_scores_mean, '.-', color="g",
             label="Cross-validation score")
    plt.legend(loc="best")
plot_curve(thresholds, clf.cv_results_, xlabel='gini thresholds')

机器学习原理与实战 | 决策树与集成算法实践

from sklearn.model_selection import GridSearchCV
entropy_thresholds = np.linspace(0, 0.01, 50)
gini_thresholds = np.linspace(0, 0.005, 50)
var = np.linspace(0,0.5,50)
# Set the parameters by cross-validation
param_grid =  [
              {'criterion': ['entropy'], 'min_impurity_decrease': entropy_thresholds},
              {'criterion': ['gini'],    'min_impurity_decrease': gini_thresholds},
              {'max_depth': range(2, 10)},
              {'min_samples_split': range(2, 30, 2)},
              {'min_samples_leaf': range(2,30,2)},
            ]
clf = GridSearchCV(DecisionTreeClassifier(), param_grid, cv=5, return_train_score=True)
clf.fit(X, y)
print("best param: {0}\nbest score: {1}".format(clf.best_params_, 
                                                clf.best_score_))
best param: {'min_samples_leaf': 8}
best score: 0.8249262444291003

2.2 决议计划树处理回归问题

在处理回归问题时,一时或许难以了解。由于自身决议计划树一般是用来处理分类使命的,可是假如区分的自己满足细,以致于在每一个区间段都有数值能够取,这儿相当于将接连值离散化以完成回归猜测。待落入小区间时再进行细化确定最终的猜测值。

在这儿运用猜测波士顿房价为比方介绍,sklearn中有自带的波士顿房价数据集:

from sklearn.datasets import load_boston
boston = load_boston()

别离取得数据与标签

X = boston.data
y = boston.target
X.shape, y.shape
((506, 13), (506,))

能够取得输入特征名

boston.feature_names
array(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
       'TAX', 'PTRATIO', 'B', 'LSTAT'], dtype='<U7')
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import BaggingRegressor, AdaBoostRegressor, RandomForestRegressor, ExtraTreesRegressor
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.10)
X_train.shape, y_train.shape, X_test.shape, y_test.shape
((455, 13), (455,), (51, 13), (51,))

运用决议计划树进行回归拟合,

cls = DecisionTreeRegressor()
cls.fit(X_train, y_train)
trainscore = cls.score(X_train,y_train)
testscore = cls.score(X_test, y_test)
print("trainscore:{}, testscore:{}".format(trainscore, testscore))
trainscore:1.0, testscore:0.8006869992064902

猜测与实在值之间的比照

testpred = cls.predict(X_test)
testpred,testpred.shape
(array([18.616,  7.971, 31.805, 14.509, 35.219, 21.286,  7.592, 14.331,
        14.021, 22.632, 19.18 , 30.344, 36.261, 21.401, 19.119, 17.553,
        23.189, 23.966, 26.453, 19.482,  8.925, 28.743, 31.395, 20.193,
        20.038, 11.777, 24.309, 20.39 , 19.515, 21.522, 19.523, 31.538,
        17.336, 27.974, 17.77 , 19.685, 23.374, 15.809, 43.124, 19.671,
        18.355, 23.843, 21.21 , 15.566, 27.845, 14.647, 29.067, 23.775,
        24.035, 23.813, 20.177]),
 (51,))
y_test,y_test.shape
(array([19.6, 10.4, 33.2, 11.8, 36.4, 20.9, 10.5, 19.1, 14.6, 21.4, 18.8,
        37. , 34.9, 21.7, 17.4, 20. , 23.2, 22.4, 25.1, 21.5,  5. , 30.7,
        23.9, 19. , 19.9, 11.8, 29.1, 19.4, 23. , 22.6, 17.5, 23.6, 27.5,
        30.8, 17.1, 17.8, 23.8, 16.7, 44. , 16.1, 18.7, 23. , 24.4, 13.3,
        23.7, 13.1, 29.8, 25. , 28.7, 28.1, 18.3]),
 (51,))

回归模型中score的判别式,核算的是猜测系数R2R^{2}

u = (y_test-testpred)**2
u = u.sum()
u
506.8415439999994
v = (y_test-y_test.mean())**2
v = v.sum()
v
2819.9364705882344
R = 1-u/v
R
0.8202649069273986

决定系数(coefficient ofdetermination),有的教材上翻译为断定系数,也称为拟合优度。

决定系数反响了y的波动有多少百分比能被x的波动所描绘,即表征依变数Y的变异中有多少百分比,可由操控的自变数X来解说。

含义:拟合优度越大,阐明x对y的解说程度越高。自变量对因变量的解说程度越高,自变量引起的变化占总变化的百分比高。观察点在回归直线附近越密集。

运用的小Tips:

当样本数量少可是样本特征十分多的时分,决议计划树很容易过拟合,一般来说,样本数比特征数多一些会比较容易建立健壮的模型 假如样本数量少可是样本特征十分多,在拟合决议计划树模型前,引荐先做维度规约,比方主成分剖析(PCA),特征挑选(Losso)或许独立成分剖析(ICA)。这样特征的维度会大大减小。再来拟合决议计划树模型作用会好。

在练习模型时,留意观察样本的类别状况(首要指分类树),假如类别散布十分不均匀,就要考虑用class_weight来约束模型过于倾向样本多的类别。

3. 集成算法

将多个分类器集成起来而形成的新的分类算法。这类算法又称元算法(meta-algorithm)。最常见的集成思维有两种bagging和boosting。

集成算法的原理是运用核算学采样原理,练习出成百上千个算法模型。当需求猜测一个新样本时,运用这些模型别离对这个样本进行猜测,然后选用大都服从少量准则,决定样本的类别。在scikit-learn中,所以的集成算法都完成在sklearn.ensemble包中。

这儿别离运用运用集成算法进行分类与回归使命测验。

3.1 分类使命测验

from sklearn.ensemble import BaggingClassifier, AdaBoostClassifier, RandomForestClassifier, ExtraTreesClassifier
X_train.shape,y_train.shape
((712, 7), (712,))
X_test.shape,y_test.shape
((179, 7), (179,))

3.1.1 自助聚合Bagging算法

根据数据随机重抽样的分类器构建办法。

cls = BaggingClassifier()
cls.fit(X,y)
trainscore = cls.score(X_train,y_train)
testscore = cls.score(X_test,y_test)
print("trainscore:{},testscore:{}".format(trainscore,testscore))
trainscore:0.9747191011235955,testscore:0.9497206703910615

3.1.2 正向鼓励Boosting算法

根据过错进步分类器功能,经过会集重视被已有分类器分类过错的样本,构建新分类器并集成。

cls = AdaBoostClassifier()
cls.fit(X,y)
trainscore = cls.score(X_train,y_train)
testscore = cls.score(X_test,y_test)
print("trainscore:{},testscore:{}".format(trainscore,testscore))
trainscore:0.8384831460674157,testscore:0.7877094972067039

3.1.3 ExtraTrees算法

cls = ExtraTreesClassifier()
cls.fit(X,y)
trainscore = cls.score(X_train,y_train)
testscore = cls.score(X_test,y_test)
print("trainscore:{},testscore:{}".format(trainscore,testscore))
trainscore:0.9831460674157303,testscore:0.9776536312849162

3.1.4 随机森林

将练习集依照横(随机抽样本)、列(随机抽特征)进行有放回的随机抽取,取得n个新的练习集,练习出n个决议计划树,经过这n个树投票决定分类成果。首要的parameters 有n_estimators 和 max_features。

cls = RandomForestClassifier()
cls.fit(X,y)
trainscore = cls.score(X_train,y_train)
testscore = cls.score(X_test,y_test)
print("trainscore:{},testscore:{}".format(trainscore,testscore))
trainscore:0.9789325842696629,testscore:0.994413407821229

测验

test.drop(['Survived'], axis=1, inplace=True)
test.head(10)
.dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; }
Pclass Sex Age SibSp Parch Fare Embarked
PassengerId
892 3 1 34.5 0 0 7.8292 0
893 3 0 47.0 1 0 7.0000 1
894 2 1 62.0 0 0 9.6875 0
895 3 1 27.0 0 0 8.6625 1
896 3 0 22.0 1 1 12.2875 1
897 3 1 14.0 0 0 9.2250 1
898 3 0 30.0 0 0 7.6292 0
899 2 1 26.0 1 1 29.0000 1
900 3 0 18.0 0 0 7.2292 2
901 3 1 21.0 2 0 24.1500 1
testpred = cls.predict(test)
test['Survived'] = testpred

输出猜测成果

test.head()
.dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; }
Pclass Sex Age SibSp Parch Fare Embarked Survived
PassengerId
892 3 1 34.5 0 0 7.8292 0 0
893 3 0 47.0 1 0 7.0000 1 0
894 2 1 62.0 0 0 9.6875 0 1
895 3 1 27.0 0 0 8.6625 1 0
896 3 0 22.0 1 1 12.2875 1 1
result = test.drop(['Pclass','Sex','Age','SibSp','Parch','Fare','Embarked'],axis=1)
result
.dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; }
Survived
PassengerId
892 0
893 0
894 1
895 0
896 1
1305 0
1306 1
1307 0
1308 0
1309 0

418 rows 1 columns

输出了一个csv表格:

result.to_csv('test.csv')

机器学习原理与实战 | 决策树与集成算法实践

在运用随机森林在kaggle提交之后,最终猜测成果为0.74162

3.2 回归使命测验

随机森林进行回归猜测

cls = RandomForestRegressor()
cls.fit(X_train, y_train)
trainscore = cls.score(X_train,y_train)
testscore = cls.score(X_test, y_test)
print("trainscore:{}, testscore:{}".format(trainscore, testscore))
trainscore:0.9839128821700205, testscore:0.8202649069273986

Bagging集成算法进行回归猜测

cls = BaggingRegressor()
cls.fit(X_train, y_train)
trainscore = cls.score(X_train,y_train)
testscore = cls.score(X_test, y_test)
print("trainscore:{}, testscore:{}".format(trainscore, testscore))
trainscore:0.9698272722986764, testscore:0.7888720521864072

参考链接: blog.csdn.net/jiaoyangwm/…