机器学习_决策树(代码片段)

author author     2022-11-10     660

关键词:

 

 

 

 

 

 

 

 

 

 

 

 

 

信息增益率=信息增益/自身熵值

 

三种方法对比:

  •  ID3的缺点,倾向于选择水平数量较多的变量,可能导致训练得到一个庞大且深度浅的树;另外输入变量必须是分类变量(连续变量必须离散化);最后无法处理空值。
  • C4.5选择了信息增益率替代信息增益。
  • CART以基尼系数替代熵;最小化不纯度而不是最大化信息增益。

 

C4.5算法核心思想是ID3算法,是ID3算法的改进,改进方面有:

  1)用信息增益率来选择属性,克服了用信息增益选择属性时偏向选择取值多的属性的不足;

  2)在树构造过程中进行剪枝

  3)能处理非离散的数据

  4)能处理不完整的数据

C4.5算法优点:产生的分类规则易于理解,准确率较高。

缺点:

  1)在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,因而导致算法的低效。

  2)C4.5只适合于能够驻留于内存的数据集,当训练集大得无法在内存容纳时程序无法运行。

 

 一定要看:决策树-https://blog.csdn.net/huanghui147258369/article/details/53689068

 

 

 

 实战:

一、概述

  决策树(Decision Tree)是有监督学习中的一种算法,并且是一种基本的分类与回归的方法。也就是说,决策树有两种:分类树和回归树。这里我们主要讨论分类树,后面再为大家讲解回归树。
什么是决策树
  让我们从养宠物开始说起~

通过上面的例子,我们很容易理解:决策树算法的本质就是树形结构,我们可以通过一些精心设计的问题,就可以对数据进行分类了。在这里,我们需要了解三个概念:

我们可以把决策树看作是一个if-then规则的集合。将决策树转换成if-then规则的过程是这样的:

  • 由决策树的根节点到叶节点的每一条路径构建一条规则
  • 路径上中间节点的特征对应着规则的条件,也叶节点的类标签对应着规则的结论

  决策树的路径或者其对应的if-then规则集合有一个重要的性质:互斥并且完备。也就是说,每一个实例都被有且仅有一条路径或者规则所覆盖。这里的覆盖是指实例的特征与路径上的特征一致,或实例满足规则的条件。

 

二、决策树的构建准备工作

  使用决策树做分类的每一个步骤都很重要,首先我们要收集足够多的数据,如果数据收集不到位,将会导致没有足够的特征去构建错误率低的决策树。数据特征充足,但是不知道用哪些特征好,也会导致最终无法构建出分类效果好的决策树。从算法方面来看的话,决策树的构建就是我们的核心内容。
  决策树如何构建呢?通常,这一过程可以概括为3个步骤:特征选择、决策树的生成和决策树的剪枝。关于剪枝部分,我会放到回归树中给大家作详细的讲解。


1.特征选择
  特征选择就是决定用哪个特征来划分特征空间,其目的在于选取对训练数据具有分类能力的特征。这样可以提高决策树学习的效率。如果利用一个特征进行分类的结果与随机分类的结果没有很大的差别,则称这个特征是没有分类能力的,经验上扔掉这些特征对决策树学习的精度影响不会很大。
  那如何来选择最优的特征来划分呢?一般而言,随着划分过程不断进行,我们希望决策树的分支节点所包含的样本尽可能属于同一类别,也就是节点的纯度(purity)越来越高。
  下面三个图表示的是纯度越来越低的过程,最后一个表示的是纯度最低的状态。
  在实际使用中,我们衡量的常常是不纯度。度量不纯度的指标有很多种,比如:熵、增益率、基尼值数。
  这里我们使用的是熵,也叫作香农熵,这个名字来源于信息论之父 克劳德·香农。


1.1 香农熵及计算函数
  熵定义为信息的期望值。在信息论与概率统计中,熵是表示随机变量不确定性的度量。
  假定当前样本集合D中一共有n类样本,第i类样本为 xi,那么xi的信息定义为:

  其中p(xi) 是选择该分类的概率。
  通过上式,我们可以得到所有类别的信息。为了计算熵,我们需要计算所有类别所有可能值包含的信息期望值(数学期望),通过下面的公式得到:

  Ent(D)的值越小,则D的不纯度就越低。

  以书上的海洋生物数据为例(表1 海洋生物数据),我们来构建数据集,并计算其香农熵:

#创建数据集
import numpy as np
import pandas as pd

def createDataSet():
    row_data = \'no surfacing\':[1,1,1,0,0],
                \'flippers\':[1,1,0,1,1],
                \'fish\':[\'yes\',\'yes\',\'no\',\'no\',\'no\']
    dataSet = pd.DataFrame(row_data)
    return dataSet

 

dataSet = createDataSet()
dataSet

 结果:

 no surfacingflippersfish
0 1 1 yes
1 1 1 yes
2 1 0 no
3 0 1 no
4 0 1 no

 

香农熵的python代码如下:

"""
函数功能:计算香农熵
参数说明:
  dataSet:原始数据集
返回:
  ent:香农熵的值
"""
def calEnt(dataSet):
    n = dataSet.shape[0] #数据集总行数
    iset = dataSet.iloc[:,-1].value_counts() #标签的所有类别
    p = iset/n #每一类标签所占比
    ent = (-p*np.log2(p)).sum() #计算信息熵
    return ent

 

calEnt(dataSet)#0.9709505944546686

 熵越高,信息的不纯度就越高。也就是混合的数据就越多。

 

 1.2 信息增益
  信息增益(Information Gain)的计算公式其实就是父节点的信息熵与其下所有子节点总信息熵之差。但这里要注意的是,此时计算子节点的总信息熵不能简单求和,而要求在求和汇总之前进行修正。

  假设离散属性a有V个可能的取值a1,a2,......,av,若使用a对样本数据集D进行划分,则会产生V个分支节点,其中第v个分支节点包含了D中所有在属性a上取值为 的样本,记为Dv我们可根据信息熵的计算公式计算出Dv信息熵,再考虑到不同的分支节点所包含的样本数不同,给分支节点赋予权重|Dv|/|D|,这就是所谓的的修正。

  所以信息增益的计算公式为:
  那我们手动计算一下,海洋生物数据集中第0列的信息增益:

a=(3/5)*(-(2/3)*np.log2(2/3)-(1/3)*np.log2(1/3))
print(calEnt(dataSet)-a)#0.4199730940219749

 

   用同样的方法,我们可以把第1列的信息增益也算出来,结果为0.17。

b=(4/5)*(-(1/2)*np.log2(1/2)-(1/2)*np.log2(1/2))
print(calEnt(dataSet)-b)#0.17095059445466854


2. 数据集最佳切分函数
  划分数据集的最大准则是选择最大信息增益,也就是信息下降最快的方向。

"""
函数功能:根据信息增益选择出最佳数据集切分的列
参数说明:
    dataSet:原始数据集
返回:
    axis:数据集最佳切分列的索引
"""

#选择最优的列进行切分
def bestSplit(dataSet):
    baseEnt = calEnt(dataSet) #计算原始熵
    bestGain = 0 #初始化信息增益
    axis = -1 #初始化最佳切分列,标签列
    for i in range(dataSet.shape[1]-1): #对特征的每一列进行循环
        levels= dataSet.iloc[:,i].value_counts().index #提取出当前列的所有取值
        ents = 0 #初始化子节点的信息熵
        for j in levels: #对当前列的每一个取值进行循环
            childSet = dataSet[dataSet.iloc[:,i]==j] #某一个子节点的dataframe
            ent = calEnt(childSet) #计算某一个子节点的信息熵
            ents += (childSet.shape[0]/dataSet.shape[0])*ent #计算当前列的信息熵
        #print(f\'第i列的信息熵为ents\')
        infoGain = baseEnt-ents #计算当前列的信息增益
        #print(f\'第i列的信息增益为infoGain\')
        if (infoGain > bestGain):
            bestGain = infoGain #选择最大信息增益
            axis = i #最大信息增益所在列的索引
    return axis

 

  通过上面手动计算,我们知道:
    第0列的信息增益为0.42,第1列的信息增益为0.17,0.42>0.17,所以我们应该选择第0列进行切分数据集。
  接下来,我们来验证我们构造的数据集最佳切分函数返回的结果与手动计算的结果是否一致。

bestSplit(dataSet)#返回的结果为0,即选择第0列来切分数据集

 

3. 按照给定列切分数据集
  通过最佳切分函数返回最佳切分列的索引,我们就可以根据这个索引,构建一个按照给定列切分数据集的函数。

"""
函数功能:按照给定的列划分数据集
参数说明:
    dataSet:原始数据集
    axis:指定的列索引
    value:指定的属性值
返回:
    redataSet:按照指定列索引和属性值切分后的数据集
"""
def mySplit(dataSet,axis,value):
    col = dataSet.columns[axis]
    redataSet = dataSet.loc[dataSet[col]==value,:].drop(col,axis=1)
    return redataSet

  验证函数,以axis=0,value=1为例 

value =1
axis=0
mySplit(dataSet,axis,value)

   结果:

 flippersfish
0 1 yes
1 1 yes
2 0 no
col = dataSet.columns[axis]
col#\'no surfacing\'

 

dataSet.loc[dataSet[col]==value,:].drop(col,axis=1)

   结果:

 flippersfish
0 1 yes
1 1 yes
2 0 no


三、递归构建决策树

  目前我们已经学习了从数据集构造决策树算法所需要的子功能模块,其工作原理如下:得到原始数据集,然后基于最好的属性值划分数据集,由于特征值可能多于两个,因此可能存在大于两个分支的数据集划分。第一次划分之后,数据集被向下传递到树的分支的下一个结点。在这个结点上,我们可以再次划分数据。因此我们可以采用递归的原则处理数据集。
  决策树生成算法递归地产生决策树,直到不能继续下去未为止。这样产生的树往往对训练数据的分类很准确,但对未知的测试数据的分类却没有那么准确,即出现过拟合现象。过拟合的原因在于学习时过多地考虑如何提高对训练数据的正确分类,从而构建出过于复杂的决策树。解决这个问题的办法是考虑决策树的复杂度,对已生成的决策树进行简化,也就是常说的剪枝处理。剪枝处理的具体讲解我会放在回归树里面。

1. ID3算法

  构建决策树的算法有很多,比如ID3、C4.5和CART,基于《机器学习实战》这本书,我们选择ID3算法。

  ID3算法的核心是在决策树各个节点上对应信息增益准则选择特征,递归地构建决策树。具体方法是:从根节点开始,对节点计算所有可能的特征的信息增益,选择信息增益最大的特征作为节点的特征,由该特征的不同取值建立子节点;再对子节点递归地调用以上方法,构建决策树;直到所有特征的信息增益均很小或没有特征可以选择为止。最后得到一个决策树。

  递归结束的条件是:程序遍历完所有的特征列,或者每个分支下的所有实例都具有相同的分类。如果所有实例具有相同分类,则得到一个叶节点。任何到达叶节点的数据必然属于叶节点的分类,即叶节点里面必须是标签。

2. 编写代码构建决策树

"""
函数功能:基于最大信息增益切分数据集,递归构建决策树
参数说明:
    dataSet:原始数据集(最后一列是标签)
返回:
    myTree:字典形式的树
"""
def createTree(dataSet):
    #print(dataSet.columns) #列名Index([\'no surfacing\', \'flippers\', \'fish\'], dtype=\'object\')
    featlist = list(dataSet.columns) #提取出数据集所有的列    [\'no surfacing\', \'flippers\', \'fish\']
    classlist = dataSet.iloc[:,-1].value_counts() #获取最后一列类标签   注:value_counts() 默认数值递减
    #判断最多标签数目是否等于数据集行数,或者数据集是否只有一列
    if classlist[0]==dataSet.shape[0] or dataSet.shape[1] == 1:
        return classlist.index[0] #如果是,返回类标签
    axis = bestSplit(dataSet) #确定出当前最佳切分列的索引
    bestfeat = featlist[axis] #获取该索引对应的特征
    myTree = bestfeat: #采用字典嵌套的方式存储树信息
    del featlist[axis] #删除当前特征
    valuelist = set(dataSet.iloc[:,axis]) #提取最佳切分列所有属性值
    for value in valuelist: #对每一个属性值递归建树
        myTree[bestfeat][value] = createTree(mySplit(dataSet,axis,value))
    return myTree

 

   查看函数运行结果:

myTree = createTree(dataSet)
myTree # \'no surfacing\': 0: \'no\', 1: \'flippers\': 0: \'no\', 1: \'yes\'

 

四、决策树的存储

  构造决策树是很耗时的任务,即使处理很小的数据集,也要花费几秒的时间,如果数据集很大,将会耗费很多计算时间。因此为了节省时间,建好树之后立马将其保存,后续使用直接调用即可。
  我这边使用的是numpy里面的save()函数,它可以直接把字典形式的数据保存为.npy文件,调用的时候直接使用load()函数即可。

#树的存储
np.save(\'myTree.npy\',myTree)

 

#树的读取
read_myTree = np.load(\'myTree.npy\').item()# np.load()加载出来的是array形式,可以利用item()将读出里边的内容
read_myTree  # \'no surfacing\': 0: \'no\', 1: \'flippers\': 0: \'no\', 1: \'yes\'

 

五、使用决策树执行分类

"""
函数功能:对一个测试实例进行分类
参数说明:
    inputTree:已经生成的决策树
    labels:存储选择的最优特征标签
    testVec:测试数据列表,顺序对应原数据集
返回:
    classLabel:分类结果
"""
def classify(inputTree,labels, testVec):
    firstStr = next(iter(inputTree)) #获取决策树第一个节点
    secondDict = inputTree[firstStr] #下一个字典
    featIndex = labels.index(firstStr) #第一个节点所在列的索引
    for key in secondDict.keys():
        if testVec[featIndex] == key:
            if type(secondDict[key]) == dict :
                classLabel = classify(secondDict[key], labels, testVec)
            else:
                classLabel = secondDict[key]
    return classLabel

 

 

labels = list(dataSet.columns)
labels#[\'no surfacing\', \'flippers\', \'fish\']

 

inputTree = myTree
inputTree#\'no surfacing\': 0: \'no\', 1: \'flippers\': 0: \'no\', 1: \'yes\'

 

firstStr = next(iter(inputTree))
firstStr#\'no surfacing\'

secondDict = inputTree[firstStr]
secondDict#0: \'no\', 1: \'flippers\': 0: \'no\', 1: \'yes\'

 

"""
函数功能:对测试集进行预测,并返回预测后的结果
参数说明:
    train:训练集
    test:测试集
返回:
    test:预测好分类的测试集
"""
def acc_classify(train,test):
    inputTree = createTree(train) #根据测试集生成一棵树
    labels = list(train.columns) #数据集所有的列名称
    result = []
    for i in range(test.shape[0]): #对测试集中每一条数据进行循环
        testVec = test.iloc[i,:-1] #测试集中的一个实例
        classLabel = classify(inputTree,labels,testVec) #预测该实例的分类
        result.append(classLabel) #将分类结果追加到result列表中
    test[\'predict\']=result #将预测结果追加到测试集最后一列
    acc = (test.iloc[:,-1]==test.iloc[:,-2]).mean() #计算准确率    .mean()用于求平均值
    print(f\'模型预测准确率为acc\')
    return test

   测试函数:

train = dataSet
test = dataSet.iloc[:3,:]

 

train

   结果:

 no surfacingflippersfish
0 1 1 yes
1 1 1 yes
2 1 0 no
3 0 1 no
4 0 1 no

 

test

   结果:

 no surfacingflippersfish
0 1 1 yes
1 1 1 yes
2 1 0 no

 

acc_classify(train,test)#模型预测准确率为1.0

 

使用SKlearn中graphviz包实现决策树的绘制

#导入相应的包
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier

 

 

#特征
Xtrain = dataSet.iloc[:,:-1]

 

Xtrain

   结果:

 no surfacingflippers
0 1 1
1 1 1
2 1 0
3 0 1
4 0 1

 

#标签
Ytrain = dataSet.iloc[:,-1]
labels = Ytrain.unique().tolist()  #numpy的tolist()方法将数组或者矩阵转换成列表

#注:sklearn要求特征为数字,所以需要把yes,no等转换为数字
Ytrain = Ytrain.apply(lambda x: labels.index(x)) #将文本转换为数字  

 

Ytrain

   结果:

0    0
1    0
2    1
3    1
4    1
Name: fish, dtype: int64
View Code

 

#训练
clf = DecisionTreeClassifier()
clf = clf.fit(Xtrain, Ytrain)

 

  经过训练,我们可以使用 export_graphviz 导出器以 Graphviz 格式导出决策树. 如果你是用 conda 来管理包,那么安装 graphviz 二进制文件和 python 包可以用以下指令安装:

conda install python-graphviz

   或者,可以从 graphviz 项目主页下载 graphviz 的二进制文件,并从 pypi 安装 Python 包装器,并安装 <cite>pip install graphviz</cite> .以下是在整个 iris 数据集上训练的上述树的 graphviz 导出示例; 其结果被保存在fish.pdf中:

import graphviz

#绘制树模型
tree.export_graphviz(clf)
dot_data = tree.export_graphviz(clf, out_file=None)
graphviz.Source(dot_data)

 

  

#给图形增加标签和颜色
dot_data = tree.export_graphviz(clf, out_file=None,
                                feature_names=[\'no surfacing\', \'flippers\'],
                                class_names=[\'fish\', \'not fish\'],
                                filled=True, rounded=True,
                                special_characters=True)
graphviz.Source(dot_data)
#sklearn利用的是cart,指标为基尼系数

 

#利用render方法生成图形
graph = graphviz.Source(dot_data)
graph.render("fish")

  fish.pdf:


  这样我们最终要的树模型就画出来啦,当然也可以手动编写函数来实现绘制树的这个过程,接下来我们一起来看看如何手动实现建树过程吧。

 

机器学习实战教程:决策树实战篇(代码片段)

一、前言上篇文章机器学习实战教程(二):决策树基础篇_M_Q_T的博客-CSDN博客讲述了机器学习决策树的原理,以及如何选择最优特征作为分类特征。本篇文章将在此基础上进行介绍。主要包括:决策树构建决... 查看详情

[机器学习与scikit-learn-15]:算法-决策树-分类问题代码详解(代码片段)

作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客本文网址:目录第1章scikit-learn对决策树的支持1.1决策树的基本原理1.2决策树的核心问题1.3 sklearn中的决策树1.4 sklearn实现... 查看详情

《机器学习实战》-决策树(代码片段)

目录决策树决策树简介决策树的构造信息增益划分数据集递归构建决策树在Python中使用Matplotlib注解绘制树形图Matplotlib注解构造注解树测试和存储分类器测试算法:使用决策树执行分类使用算法:决策树的存储示例:使用决策树... 查看详情

机器学习之路--决策树(代码片段)

...使用不熟悉的数据集合,并从中提取一系列规则,在这些机器根据数据集创建规则是,就是机器学习的过程。二,相关知识1决 查看详情

机器学习—决策树(代码片段)

一、原理部分:还是图片显示~  二、sklearn实现1、回归树importpandasaspdimportnumpyasnpimportmatplotlib.pyplotaspltimportmatplotlibasmplimportseabornassnsmpl.rcParams[‘font.sans-serif‘]=[u‘SimHei‘]mpl.rcParams[‘axe 查看详情

机器学习-决策树(代码片段)

最近在看周志华的《机器学习》,感觉讲的还是条理清晰,循序渐进的。但是只是看了很快概念就混淆,导致脑子里一片混乱,所以准备将看过的内容及学到的东西放在这里和大家相互学习交流。  本文转自:http://blog.csdn.net/... 查看详情

机器学习——决策树(代码片段)

1、介绍决策树是一种依托决策而建立起来的一种树。在机器学习中,决策树是一种预测模型,代表的是一种对象属性与对象值之间的一种映射关系,每一个节点代表某个对象/分类,树中的每一个分叉路径代表某个可能的属性值... 查看详情

机器学习实战之一---简单讲解决策树(代码片段)

机器学习实战之一---简单讲解决策树https://blog.csdn.net/class_brick/article/details/78855510 前言:本文基于《机器学习实战》一书,采用python语言,对于机器学习当中的常用算法进行说明。  一、综述定义:首先来对决策树进... 查看详情

机器学习算法学习02:决策树的学习以及应用决策树解决cora数据集论文分类问题(代码片段)

机器学习算法学习02:决策树的学习以及应用决策树解决Cora数据集论文分类问题文章目录机器学习算法学习02:决策树的学习以及应用决策树解决Cora数据集论文分类问题1.前言2.算法分析2.1算法概述2.2算法优化3.算法代码3.... 查看详情

决策树

...ferenceblog:https://blog.csdn.net/jiaoyangwm/article/details/79525237#t0(机器学习实战简略版,更容易懂,附在下面)###2.referencebook:《机器学习实战》###3.Sklearn实现决策树并用Graphviz可视化决策树(一个例子):https://blog.csdn.net/zhyh1435589631/artic... 查看详情

机器学习回归决策树(代码片段)

回归决策树1.原理概述2.算法描述3.简单实例3.1实例计算过程3.2回归决策树和线性回归对比4.小结1.原理概述上篇文章已经讲到,关于数据类型,我们主要可以把其分为两类,连续型数据和离散型数据。在面对不同数据... 查看详情

机器学习实战基础(二十八):决策树概述(代码片段)

概述决策树是如何工作的 决策树(DecisionTree)是一种非参数的有监督学习方法,它能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题。决策树算法容易理解,适... 查看详情

机器学习决策树分类原理(代码片段)

决策树分类原理1.熵1.1概念1.2案例2.决策树的划分依据2.1信息增益2.1.1概念2.1.2案例2.2信息增益率2.2.1概念2.2.2案例案例一案例二2.2.3为什么使用C4.5要好?2.3基尼值和基尼指数2.3.1概念2.3.2案例3.小结3.1常见决策树的启发函数比较3.1.1ID3... 查看详情

机器学习回归决策树算法(代码片段)

目录1原理概述2算法描述3简单实例3.1实例计算过程3.2回归决策树和线性回归对比4小结1原理概述前面已经讲到,关于数据类型,我们主要可以把其分为两类,连续型数据和离散型数据。在面对不同数据时,决策树... 查看详情

机器学习sklearn监督学习分类算法决策树decisiontree(代码片段)

#导入鸢尾花数据集、决策树分类器、计算交叉验证值的函数cross_val_scorefromsklearn.datasetsimportload_irisfromsklearn.treeimportDecisionTreeClassifierfromsklearn.model_selectionimportcross_val_score#使用默认参数,创建一颗基于基尼系数的决策树&# 查看详情

我的机器学习之旅:决策树(代码片段)

决策树概念:分类决策树模型是一种描述对实例进行分类的树形结构。决策树由结点和有向边组成。结点有两种类型:内部节点和叶节点,内部节点表示一个特征或属性,叶节点表示一个类。 分类的时候,从根节点开始,对... 查看详情

机器学习决策树算法泰坦尼克号乘客生存预测(代码片段)

目录1决策树算法api2泰坦尼克号乘客案例背景2.1步骤分析2.2代码实现2.3决策树可视化2.3.1保存树的结构到dot文件2.3.2网站显示结构3决策树总结4小结1决策树算法apiclasssklearn.tree.DecisionTreeClassifier(criterion=’gini’,max_depth=None,rando... 查看详情

机器学习决策树算法泰坦尼克号乘客生存预测(代码片段)

目录1决策树算法api2泰坦尼克号乘客案例背景2.1步骤分析2.2代码实现2.3决策树可视化2.3.1保存树的结构到dot文件2.3.2网站显示结构3决策树总结4小结1决策树算法apiclasssklearn.tree.DecisionTreeClassifier(criterion=’gini’,max_depth=None,rando... 查看详情