数据科学(DS)学习笔记-决策树

一. 什么是决策树

决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。


image.png

如图即为最简单的决策树

二.决策树名词

1.根节点:最顶部的那个节点
2.叶子节点:每条路径最末尾的那个节点,也就是最外层的节点
3.非叶子节点:一些条件的节点,下面会有更多分支,也叫做分支节点
4.分支:也就是分叉


image.png

三.决策树的判断-信息熵

先看一下信息熵的公式:


image.png

其中:𝑝(𝑥𝑖)代表随机事件𝑥𝑖的概率。

首先了解一下信息量:信息量是对信息的度量,就跟时间的度量是秒一样,当我们考虑一个离散的随机变量 x 的时候,当我们观察到的这个变量的一个具体值的时候,我们接收到了多少信息呢?

多少信息用信息量来衡量,我们接受到的信息量跟具体发生的事件有关。

信息的大小跟随机事件的概率有关。越小概率的事情发生了产生的信息量越大,如孝感发生的地震了;越大概率的事情发生了产生的信息量越小,如太阳从东边升起来了(肯定发生嘛, 没什么信息量)。这很好理解!

因此一个具体事件的信息量应该是随着其发生概率而递减的,且不能为负。
因此我们就得到信息量的公式为:


image.png

信息量度量的是一个具体事件发生了所带来的信息,而熵则是在结果出来之前对可能产生的信息量的期望——考虑该随机变量的所有可能取值,即所有可能发生事件所带来的信息量的期望


image.png

转换一下:
image.png

四.决策树与实践

我们以小明起床为例:
我们随机抽了一年中14天小明的赖床情况


image.png

可以发现,数据中有三个属性会影响到最终的结果,分别是,季节,时间是否过8点,风力情况


image.png

在计算每一个属性的信息熵之前,我们需要先根据历史数据,计算没有任何属性影响下的赖床信息熵。从数据我们可以知道,12天中,有赖床为8天,不赖床为4天。则

p(赖床) = 8 / 12
p(不赖床) = 4 / 12.

信息熵为:
H(赖床) =-(p(赖床) * log(p(赖床)) + p(不赖床) * log(p(不赖床))) 
= -((8/12)*log(8/12)+(6/12)*log(6/12)
=0.918

接下来就可以来计算每个属性的信息熵了,这里有三个属性,即季节,是否过早上8点,风力情况,我们需要计算三个属性的每个属性在不同情况下,赖床和不赖床的概率,以及熵值。
我们以风力情况为例:

风力情况为 breeze 时,有 4 / 5 的概率会赖床,而 1 / 5 的概率不会赖床
熵为 entropy(breeze) =0.722

风力情况为 no wind 时
熵值为 entropy(no wind) = 0.811

风力情况为 gale 时,熵值为  entropy(gale) = 0.918

总的风力熵值为:
5/12 * 0.722 + 4/12 * 0.811 + 3/12 *  0.918 = 0.801

显然通过计算我们发现,在风力分类的情况下,赖床的熵值降低了,说明什么呢?
说明我们的信息混乱程度降低

image.png

以同样的计算方式,我们可以求出另外两个属性的信息熵:

H(季节) = 0.56
H(是否过 8 点) = 0.748

显然通过发现

0.56<0.748<0.801
季节<是否过8点<风力

很明显,信息增益最大的是季节这个属性


image.png

通过遍历既可以算出不同属性的增益情况
即可以得到如下决策树图


image.png

四.过拟合和欠拟合

image.png

剪枝,即减少树的高度就是为了解决过拟合
从而降低噪音对数据分类的影响
而剪枝又分两种方法,预剪枝干,和后剪枝。这两种方法其实还是蛮好理解的,一种是自顶向下,一种是自底向上。我们分别来看看。

预剪枝
预剪枝其实你可以想象成是一种自顶向下的方法。在构建过程中,我们会设定一个高度,当达构建的树达到那个高度的时候呢,我们就停止建立决策树,这就是预剪枝的基本原理。

后剪枝
后剪枝呢,其实就是一种自底向上的方法。它会先任由决策树构建完成,构建完成后呢,就会从底部开始,判断哪些枝干是应该剪掉的。

注意到预剪枝和后剪枝的最大区别没有,预剪枝是提前停止,而后剪枝是让决策树构建完成的,所以从性能上说,预剪枝是会更块一些,后剪枝呢则可以更加精确。
决策树优缺点
优点:
(1)速度快: 计算量相对较小, 且容易转化成分类规则. 只要沿着树根向下一直走到叶, 沿途的分裂条件就能够唯一确定一条分类的谓词.
(2)准确性高: 挖掘出来的分类规则准确性高, 便于理解, 决策树可以清晰的显示哪些字段比较重要, 即可以生成可以理解的规则.
(3)可以处理连续和种类字段
(4)不需要任何领域知识和参数假设
(5)适合高维数据
缺点:
(1)对于各类别样本数量不一致的数据, 信息增益偏向于那些更多数值的特征
(2)容易过拟合
(3)忽略属性之间的相关性

五.决策树的实际应用

DecisionTreeClassifier(criterion="gini",
                 splitter="best",
                 max_depth=None,
                 min_samples_split=2,
                 min_samples_leaf=1,
                 min_weight_fraction_leaf=0.,
                 max_features=None,
                 random_state=None,
                 max_leaf_nodes=None,
                 min_impurity_decrease=0.,
                 min_impurity_split=None,
                 class_weight=None,
                 presort=False)

参数含义:
1.criterion:string, optional (default="gini")
            (1).criterion='gini',分裂节点时评价准则是Gini指数。
            (2).criterion='entropy',分裂节点时的评价指标是信息增益。
2.max_depth:int or None, optional (default=None)。指定树的最大深度。
            如果为None,表示树的深度不限。直到所有的叶子节点都是纯净的,即叶子节点
            中所有的样本点都属于同一个类别。或者每个叶子节点包含的样本数小于min_samples_split。
3.splitter:string, optional (default="best")。指定分裂节点时的策略。
           (1).splitter='best',表示选择最优的分裂策略。
           (2).splitter='random',表示选择最好的随机切分策略。
4.min_samples_split:int, float, optional (default=2)。表示分裂一个内部节点需要的做少样本数。
           (1).如果为整数,则min_samples_split就是最少样本数。
           (2).如果为浮点数(0到1之间),则每次分裂最少样本数为ceil(min_samples_split * n_samples)
5.min_samples_leaf: int, float, optional (default=1)。指定每个叶子节点需要的最少样本数。
           (1).如果为整数,则min_samples_split就是最少样本数。
           (2).如果为浮点数(0到1之间),则每个叶子节点最少样本数为ceil(min_samples_leaf * n_samples)
6.min_weight_fraction_leaf:float, optional (default=0.)
           指定叶子节点中样本的最小权重。
7.max_features:int, float, string or None, optional (default=None).
           搜寻最佳划分的时候考虑的特征数量。
           (1).如果为整数,每次分裂只考虑max_features个特征。
           (2).如果为浮点数(0到1之间),每次切分只考虑int(max_features * n_features)个特征。
           (3).如果为'auto'或者'sqrt',则每次切分只考虑sqrt(n_features)个特征
           (4).如果为'log2',则每次切分只考虑log2(n_features)个特征。
           (5).如果为None,则每次切分考虑n_features个特征。
           (6).如果已经考虑了max_features个特征,但还是没有找到一个有效的切分,那么还会继续寻找
           下一个特征,直到找到一个有效的切分为止。
8.random_state:int, RandomState instance or None, optional (default=None)
           (1).如果为整数,则它指定了随机数生成器的种子。
           (2).如果为RandomState实例,则指定了随机数生成器。
           (3).如果为None,则使用默认的随机数生成器。
9.max_leaf_nodes: int or None, optional (default=None)。指定了叶子节点的最大数量。
           (1).如果为None,叶子节点数量不限。
           (2).如果为整数,则max_depth被忽略。
10.min_impurity_decrease:float, optional (default=0.)
         如果节点的分裂导致不纯度的减少(分裂后样本比分裂前更加纯净)大于或等于min_impurity_decrease,则分裂该节点。
         加权不纯度的减少量计算公式为:
         min_impurity_decrease=N_t / N * (impurity - N_t_R / N_t * right_impurity
                            - N_t_L / N_t * left_impurity)
         其中N是样本的总数,N_t是当前节点的样本数,N_t_L是分裂后左子节点的样本数,
         N_t_R是分裂后右子节点的样本数。impurity指当前节点的基尼指数,right_impurity指
         分裂后右子节点的基尼指数。left_impurity指分裂后左子节点的基尼指数。
11.min_impurity_split:float
         树生长过程中早停止的阈值。如果当前节点的不纯度高于阈值,节点将分裂,否则它是叶子节点。
         这个参数已经被弃用。用min_impurity_decrease代替了min_impurity_split。
12.class_weight:dict, list of dicts, "balanced" or None, default=None
         类别权重的形式为{class_label: weight}
         (1).如果没有给出每个类别的权重,则每个类别的权重都为1。
         (2).如果class_weight='balanced',则分类的权重与样本中每个类别出现的频率成反比。
         计算公式为:n_samples / (n_classes * np.bincount(y))
         (3).如果sample_weight提供了样本权重(由fit方法提供),则这些权重都会乘以sample_weight。
13.presort:bool, optional (default=False)
        指定是否需要提前排序数据从而加速训练中寻找最优切分的过程。设置为True时,对于大数据集
        会减慢总体的训练过程;但是对于一个小数据集或者设定了最大深度的情况下,会加速训练过程。

通常来说,较为重要的参数有:

criterion:用以设置用信息熵还是基尼系数计算。
splitter:指定分支模式
max_depth:最大深度,防止过拟合
min_samples_leaf:限定每个节点分枝后子节点至少有多少个数据,否则就不分枝

5.1 准备数据及读取
数据就是上次说到的赖床特征,
季节 | 时间已过 8 点 | 风力情况 | 要不要赖床
将它存储成 csv 文件

spring,no,breeze,yes
winter,no,no wind,yes
autumn,yes,breeze,yes
winter,no,no wind,yes
summer,no,breeze,yes
winter,yes,breeze,yes
winter,no,gale,yes
winter,no,no wind,yes
spring,yes,no wind,no
summer,yes,gale,no
summer,no,gale,no
autumn,yes,breeze,no
import pandas as pd
from sklearn.feature_extraction import DictVectorizer
from sklearn import tree
from sklearn.model_selection import train_test_split

#pandas 读取 csv 文件,header = None 表示不将首行作为列
data = pd.read_csv('data/laic.csv',header =None)
#指定列
data.columns = ['season','after 8','wind','lay bed']

#sparse=False意思是不产生稀疏矩阵
vec=DictVectorizer(sparse=False)
#先用 pandas 对每行生成字典,然后进行向量化
feature = data[['season','after 8','wind']]
X_train = vec.fit_transform(feature.to_dict(orient='record'))
#打印各个变量
print('show feature\n',feature)
print('show vector\n',X_train)
print('show vector name\n',vec.get_feature_names())
show feature
     season after 8     wind
0   spring      no   breeze
1   winter      no  no wind
2   autumn     yes   breeze
3   winter      no  no wind
4   summer      no   breeze
5   winter     yes   breeze
6   winter      no     gale
7   winter      no  no wind
8   spring     yes  no wind
9   summer     yes     gale
10  summer      no     gale
11  autumn     yes   breeze
show vector
 [[1. 0. 0. 1. 0. 0. 1. 0. 0.]
 [1. 0. 0. 0. 0. 1. 0. 0. 1.]
 [0. 1. 1. 0. 0. 0. 1. 0. 0.]
 [1. 0. 0. 0. 0. 1. 0. 0. 1.]
 [1. 0. 0. 0. 1. 0. 1. 0. 0.]
 [0. 1. 0. 0. 0. 1. 1. 0. 0.]
 [1. 0. 0. 0. 0. 1. 0. 1. 0.]
 [1. 0. 0. 0. 0. 1. 0. 0. 1.]
 [0. 1. 0. 1. 0. 0. 0. 0. 1.]
 [0. 1. 0. 0. 1. 0. 0. 1. 0.]
 [1. 0. 0. 0. 1. 0. 0. 1. 0.]
 [0. 1. 1. 0. 0. 0. 1. 0. 0.]]
show vector name
 ['after 8=no', 'after 8=yes', 'season=autumn', 'season=spring', 'season=summer', 'season=winter', 'wind=breeze', 'wind=gale', 'wind=no wind']

通过DictVectorizer,我们就能够把字符型的数据,转化成0 1的矩阵,方便后面进行运算。额外说一句,这种转换方式其实就是one-hot编码。
5.2决策树训练

#划分成训练集,交叉集,验证集,不过这里我们数据量不够大,没必要
#train_x, test_x, train_y, test_y = train_test_split(X_train, Y_train, test_size = 0.3)
#训练决策树
clf = tree.DecisionTreeClassifier(criterion='gini')
clf.fit(X_train,Y_train)

#保存成 dot 文件,后面可以用 dot out.dot -T pdf -o out.pdf 转换成图片
with open("out.dot", 'w') as f :
    f = tree.export_graphviz(clf, out_file = f,
            feature_names = vec.get_feature_names())

最后差不多就这个样子了
参考:
https://www.cnblogs.com/listenfwind/p/11310924.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 1、此生与君共,万世千生。比翼双飞,不思归。 2、回忆里你很干净,比酒淡,比水清。 3、小生不才,未得姑娘青睐,扰...
    H树洞_轻阅听写阅读 689评论 0 0
  • 周末带孩子去海边。 新的沙滩玩具到了,宝宝兴冲冲要去堆沙堡、扔石头,然后又发现海滩上有很多小海螺,开心地捡了一小桶...
    夜心婉阅读 115评论 0 0
  • 据统计数据,全国2.7亿个家庭中,有30%的已婚妇女曾遭受家暴。平均每7.4秒就会有一位女性受到丈夫殴打。 我国每...
    廖天鹏阅读 1,738评论 0 0
  • 近日雾霾严重,各地网友纷纷要求为PM2.5定一个科学恰当的中文名。网友答案真是百花齐放: 严肃一点的叫‘公雾源’;...
    人诚品真阅读 124评论 0 0