机器学习:sklearn实现决策树和随机森林

  • 15.决策树理解
  • 16.决策树之信息熵
  • 17.决策树之信息熵补充
  • 18.决策树之信息增益
  • 19.决策树之算法选择(ID3,C4.5,CART)
  • 20.决策树算法之预剪枝和后剪枝
  • 21.实战-泰坦尼克号获救预测(1)
  • 22.实战-泰坦尼克号获救预测(2)
  • 23.决策树的绘制
  • 24.随机森林原理
  • 25.sklearn实现随机森林

决策树理解

对于决策树的发展看其分化指标的变化即可:

信息熵(决策树)–》信息增益(ID3)–》信息增益率(C4.5)–》基尼指数(CART)

指标计算的对象是每个特征
在这里插入图片描述
决策树对连续型数据特征的处理:
一种属性取值是连续的,我们可以将其表示为比如(X>a)或(X<=a)的形式,将其离散化。比如我们可以把年龄分成【0,18】,【19,28】,【29,38】等,
可是一般,我没有分桶啊,为什么直接训练了

决策树理解:

假如现在有一个母亲给女儿找相亲对象的这么一段对话:

女儿:多大年纪了?
母亲:26。
女儿:长的帅不帅?
母亲:挺帅的。
女儿:收入高不?
母亲:不算很高,中等情况。
女儿:是公务员不?
母亲:是,在税务局上班呢。
女儿:那好,我去见见。

那么转换成图便是这样:
机器学习:sklearn实现决策树和随机森林_第1张图片

以上这个就是决策树的原理。通过不断的划分条件来进行分类。其中决策树最关键的,是找出那些对结果影响最大的条件,放到前面。比如以上如果年龄是女儿最看重的,那么就应该把年龄放到最前面,这样可以节省查找的次数

决策树之信息熵

信息熵:

信息熵是1948年美国数学家香农提出的概念,他是用来表示随机数据不确定性的度量。信息熵越大,也就意味着越不稳定,信息熵越小,说明数据是越稳定(越接近或者类似)。

信息熵的公式是:信息熵的公式里面为什么有log2,因为log函数符合信息熵的定义:信息熵越大,也就意味着越不稳定,信息熵越小,说明数据是越稳定(越接近或者类似)。

在这里插入图片描述
p在(0,1)之间,信息熵是log函数取负值,所以p趋近于0,则log趋向于无穷大;p趋近于1,则log趋向于0;表现出了信息熵越大,也就意味着越不稳定,信息熵越小,说明数据是越稳定。
机器学习:sklearn实现决策树和随机森林_第2张图片

其中H(x)就表示信息熵,P(F1,F2...)表示数据在整个数据集中出现的概率。

比如有两组数据:

A = [1,1,1,1,1,1,1,1,2,2]
B = [1,2,3,4,5,6,7,8,9,10]

我们先不去算信息熵,从数据上就能看出,A是更稳定的,B的数据更杂,猜想A的信息熵比B的信息熵要小。那么通过计算信息熵来确定是不是真的:

H(A) = -(8/10*log(8/10)+2/10*log(2/10)) = 0.7219280948873623
H(B) = -(1/10*log(1/10)*10) = 3.321928094887362

可以看出B的信息熵明显比A的信息熵大很多。

信息熵越小,越容易分类,就越重要,越放在前面分类

决策树之信息熵补充

信息熵的补充:

  1. 信息熵的单位是比特(bit)就是我们在编程中用来计算数据大小的单位。1位=8比特
  2. 公式中的log2的理解:我们先看下log2的图:
    机器学习:sklearn实现决策树和随机森林_第3张图片
    其中x就是概率,y就是log2(x)的值,0,如果x越大,那么信息熵也就越小,而x越小,则信息熵越大。正好是和我们期望的是一样的。

决策树之信息增益

信息增益:

信息增益表示特征X使得类Y的不确定性减少的程度。因此信息增益越大,那么表示对不确定性减少得越多,也就越能更清晰的分类。特征A对训练数据集D的信息增益记作g(D,A),定义为集合D的信息熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差,即公式为:

g(D,A)=H(D)−H(D∣A)
# 其中的H(D|A),A特征中可能有N种值(A1,A2...),计算方式如下
H(D|A) = P(A1)*H(D|A1) + P(A2)*H(D|A2)...

根据信息增益的准则的特征选择方法是:对于训练数据集D,计算其每个特征的信息增益,并比较它们的信息增益,选择信息增益最大的特征。

贷款案例信息增益:

机器学习:sklearn实现决策树和随机森林_第4张图片

以上数据集中,有年龄是否有工作是否有房子信贷情况4个特征来判断是否应该给这个用户贷款,当时放到决策树中,我们应该要把哪个特性放到前面,哪个特性放到后面,就应该通过计算信息增益来决定。

H(贷款) = -(6/15*log2(6/15)+9/15*log2(9/15)) = 0.97
H(贷款|年龄) = H(贷款) - H(贷款|青年) - H(贷款|中年) - H(贷款|老年)
H(贷款|青年) = -5/15*(2/5*log2(2/5) + 3/5*log2(3/5)) = 0.32
H(贷款|中年) = -5/15*(2/5*log2(2/5) + 3/5*log2(3/5)) = 0.32
H(贷款|老年) = -5/15*(1/5*log2(1/5) + 4/5*log2(4/5)) = 0.24

因此H(贷款|年龄) = 0.97 - (0.32+0.32+0.24) = 0.09

同理我们也可以计算出是否有工作的信息增益为0.32、是否有房子的信息增益为0.42、信贷情况的信息增益为0.363。因此在建立决策树的时候就可以根据信息增益的从大到小排序了。

决策树之算法选择(ID3,C4.5,CART)

决策树算法选择:

ID3:

ID3算法采用的是信息增益来进行决策树的创建的。信息增益虽然效果不错,但是他是偏向选择分支多的属性,会导致过度拟合,因此一般不会采用此算法。

比如 把ID作为特征属性,会导致ID信息增益最大,但事实ID属性在分类上,基本没有作用

C4.5:

ID3会导致过度拟合,那么我们能想到的解决办法自然就是对分支过多的情况进行惩罚。于是我们有了信息增益比,或者说信息增益率,信息增益率:

gr = 某特征的信息增益/某特征的信息熵
gr=(H(c)−H(c|X))/H(X)

从上述公式我们可以看到,如果某特征分类特别多,那么会导致信息熵会非常大,从而信息增益也会变得比较大,因此最后得出的信息增益率会变小,这样就对他进行了有效抑制。

CART:

C4.5已经是比较好的构建决策树的算法了,但是他计算的时候需要不断的求对数(log),对算法的效率有一定的影响,因此在CART中采用了一个叫做基尼(Gini)系数的东西来进行分类。Gini系数是一种与信息熵类似的做特征选择的方式,可以用来数据的不纯度。Gini系数的计算方式如下:

Gini(p)=1−(P1^2+P2^2+...)

其中P(n)代表的是第几个特征出现的概率。

基尼指数越小越好

决策树算法之预剪枝和后剪枝

预剪枝和后剪枝:

机器学习:sklearn实现决策树和随机森林_第5张图片
树的层级和叶子节点不能过于复杂,如果过于复杂,那么容易导致过拟合现象(过拟合:在训练的时候得分很高,但是测试的时候得分很低)。而预剪枝和后剪枝手段,都是为了防止决策树太复杂的手段:

预剪枝:

预剪枝就是在决策树的建立过程中不断的调节,可以调节的条件有:

  1. 数的深度:如果在决策树建立过程中,发现深度超过指定的值,那么就不再分了。
  2. 叶子节点个数:同上。
  3. 叶子节点样本数:如果某个叶子节点的个数已经低于指定的值,那么就不会再分了。
  4. 信息增益量/Gini系数:计算信息增益量或者Gini系数,如果小于指定的值,那么也不会再分了。

以上的参数,都需要在建模的过程中,不断的调节,来达到最优。

预剪枝可以有效的降低过拟合现象,并且因为是在决策树建立的过程中进行调节,因此显著的减少了训练时间开销和测试时间的开销。另外因为预剪枝是通过限制一些建树的条件来实现的,这种方式容易导致(欠拟合:模型训练得不够好)的现象。

后剪枝:

后剪枝就是在决策树建立完成后再进行的,根据以下公式:

C = gini*samples + α*叶子节点个数

C表示损失,C越大,表示损失越多,我们要选择损失小的。
其中的α我们是可以调节的,如果α越大,那么叶子结点个数越多的,损失越大。因此α值越大,那么偏向叶子节点少的。α越小,那么偏向叶子节点多的。

后剪枝通常比预剪枝保留更多的分支,因此欠拟合风险比预剪枝要小,但是因为后剪枝是在树建立完成后再自底向上对所有非叶子节点进行逐一考察,因此训练时间开销比预剪枝要大得多。

sklearn实现决策树:

sklearn中,可以通过sklearn.tree.DecisionTreeClassifier来实现决策树,这个类有以下参数:

  1. criteriongini或者entropy的方式。
  2. splitterbestrandombest是在所有特种中找最好的切分点,random是随机的找一些特征来进行切分(数据量大的时候用random
  3. max_depth:树的最大深度。当特征或者数据量比较小的时候可以不用管这个值。特征比较多的时候可以尝试限制一下。
  4. min_samples_split:决策树中某个叶子节点的样本最小个数。如果数据量不大,不需要管这个值,如果样本量比较大,则推荐增大这个值。
  5. min_weight_fraction_leaf:叶子节点所有样本权重和的最小值。如果小于这个值,则会和兄弟节点一起被剪枝,默认是0,也就是不考虑权重的问题。一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了。
  6. max_leaf_nodes:最大的叶子节点的个数。默认是None,即不限制叶子节点的个数。如果设置了这个值,那么在决策树建立的过程中优化叶子节点的个数。如果特征不多,可以不考虑这个值,但是如果特征分多的话,可以加以限制。
  7. class_weight:指定样本各特征的权重,主要是为了方式某些特征的样本过多导致偏向这些特征。默认是balance,也就是算法会自动的调节权重。
  8. min_impurity_decrease:最小的不纯度(基尼系数、信息增益等)。如果小于这个数,那么就不会再往下生成叶子节点了。

实战-泰坦尼克号获救预测(1)

## 决策树案例-泰坦尼克号获救预测:

import pandas as pd
from sklearn.tree import DecisionTreeClassifier,export_graphviz
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer


titanic = pd.read_csv("data/titanic.txt")
features = titanic[['pclass','age','sex']]
# 处理年龄的缺失值,用平均年龄来代替
features['age'].fillna(features['age'].mean(),inplace=True)

targets = titanic['survived']
targets.head()

X_train,X_test,y_train,y_test = train_test_split(features,targets,test_size=0.25)

# 特征抽取:字典的特征抽取
vect = DictVectorizer()
X_train = vect.fit_transform(X_train.to_dict(orient="records"))
X_test = vect.fit_transform(X_test.to_dict(orient="records"))
print(vect.get_feature_names())

classifier = DecisionTreeClassifier()
# fit方法只能处理数值类型
classifier.fit(X_train,y_train)
classifier.score(X_test,y_test)


数据抽取(处理离散型字符数据):
机器学习:sklearn实现决策树和随机森林_第6张图片

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer
import numpy as np

titanic = pd.read_csv("data/titanic.txt")
features = titanic[['pclass','age','sex']]
features['age'].fillna(features['age'].mean(),inplace=True)
targets = titanic['survived']

X_train,X_test,y_train,y_test = train_test_split(features,targets,test_size=0.25)
# 特征抽取:字典的特征抽取
vect = DictVectorizer(sparse=False)
X_train = vect.fit_transform(X_train.to_dict(orient='records'))
X_test = vect.transform(X_test.to_dict(orient="records"))

tree = DecisionTreeClassifier()
tree.fit(X_train,y_train)
tree.score(X_test,y_test)

实战-泰坦尼克号获救预测(2)

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer
import numpy as np

titanic = pd.read_csv("data/titanic.txt")
features = titanic[['pclass','age','sex']]
features['age'].fillna(features['age'].mean(),inplace=True)
targets = titanic['survived']

X_train,X_test,y_train,y_test = train_test_split(features,targets,test_size=0.25)

vect = DictVectorizer(sparse=False)
# X_train.to_dict
X_train = vect.fit_transform(X_train.to_dict(orient='records'))
X_test = vect.transform(X_test.to_dict(orient="records"))

tree = DecisionTreeClassifier()
tree.fit(X_train,y_train)
tree.score(X_test,y_test)

X_train.to_dict(orient=‘records’):
机器学习:sklearn实现决策树和随机森林_第7张图片

决策树的绘制

绘制决策树:

决策树训练完成后,如果能直观的看到树的结构,那么会帮助我们更好的理解树的构建情况以及帮助我们做一些剪枝的操作。在sklearn中,可以通过sklearn.tree.export_graphviz来将树结构导出为.dot文件,然后再到这个网站:https://www.graphviz.org/download/下载graphviz软件,这个软件可以将.dot文件转为png格式。graphviz安装完成后,记得把安装路径下的bin目录,添加到环境变量PATH中。然后再在cmd终端使用命令dot -Tpng 生成的dot文件.dot -o tree.pngdot文件转换为png文件。

其中sklearn.tree.export_graphviz函数有许多参数,我们了解下以下几个参数:

  1. decision_tree:决策树,就是DecisionTreeClassifier的对象。
  2. out_file:生成.dot文件的路径。
  3. feature_names:特征名称,方便在生成树的时候能在节点看到特征名称。通过get_feature_names来获取,不能乱填。
  4. class_names:分类的类名。如果设置了,他是按照target分类的数值从小到大进行排序,所以在指定具体名称的时候,应该根据排序的顺序来。

示例代码如下:

export_graphviz(classifier,"tree.dot",feature_names=['age', '1st', '2nd', '3rd', 'female', 'male'],class_names=['die','live'])

随机森林原理

集成算法之随机森林:

集成算法包含(bagging-袋/boosting-增强/stacking-堆叠)在机器学习中,随机森林是一个包含多个决策树的分类器,并且其输出的类别是由个别树输出的类别的众数而定。利用相同的训练数搭建多个独立的分类模型,然后通过投票的方式,以少数服从多数的原则作出最终的分类决策。例如, 如果你训练了5个树, 其中有4个树的结果是True, 1个数的结果是False, 那么最终结果会是True.

在前面的决策当中我们提到,一个标准的决策树会根据每维特征对预测结果的影响程度进行排序,进而决定不同的特征从上至下构建分裂节点的顺序,如此以来,所有在随机森林中的决策树都会受这一策略影响而构建的完全一致,从而丧失的多样性。所以在随机森林分类器的构建过程中,每一棵决策树都会放弃这一固定的排序算法,转而随机选取特征。

学习算法:

  1. N来表示训练用例(样本)的个数,M表示特征数目。
  2. 输入特征数目m,用于确定决策树上一个节点的决策结果;其中m应远小于M
  3. N个训练用例(样本)中以有放回抽样的方式,取样N次,形成一个训练集(即bootstrap取样),并用未抽到的用例(样本)作预测,评估其误差。
  4. 对于每一个节点,随机选择m个特征,决策树上每个节点的决定都是基于这些特征确定的。根据这m个特征,计算其最佳的分裂方式。

理解:

为什么要随机抽样训练集?

如果不进行随机抽样,每棵树的训练集都一样,那么最终训练出的树分类结果也是完全一样的

为什么要有放回地抽样?

如果不是有放回的抽样,那么每棵树的训练样本都是不同的,都是没有交集的,这样每棵树都是“有偏的”,都是绝对“片面的”(当然这样说可能不对),也就是说每棵树训练出来都是有很大的差异的;而随机森林最后分类取决于多棵树(弱分类器)的投票表决。

sklearn实现随机森林

sklearn实现随机森林:

class sklearn.ensemble.RandomForestClassifier(n_estimators=10, criterion=’gini’,max_depth=None, bootstrap=True, random_state=None)

参数介绍:

  1. n_estimatorsintegeroptional(default = 10)森林里的树木数量。
  2. criteriastring,可选(default =“gini”)分割特征的测量方法。
  3. max_depthintegerNone,可选(默认=无)树的最大深度 。
  4. bootstrapbooleanoptional(default = True)是否在构建树时使用放回抽样。
import pandas as pd
from sklearn.tree import DecisionTreeClassifier,export_graphviz
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer
from sklearn.ensemble import RandomForestClassifier

titanic = pd.read_csv("data/titanic.txt")
features = titanic[['pclass','age','sex']]
# 处理年龄的缺失值,用平均年龄来代替
features['age'].fillna(features['age'].mean(),inplace=True)
targets = titanic['survived']

X_train,X_test,y_train,y_test = train_test_split(features,targets,test_size=0.25)

vect = DictVectorizer()
X_train = vect.fit_transform(X_train.to_dict(orient="records"))
X_test = vect.fit_transform(X_test.to_dict(orient="records"))

rf = RandomForestClassifier(n_estimators=100)
rf.fit(X_train,y_train)
rf.score(X_test,y_test)

你可能感兴趣的:(机器学习:sklearn实现决策树和随机森林)