《Machine Learning in Action》—— Taoye给你讲讲决策树到底是支什么“鬼”

前面我们已经详细讲解了线性SVM以及SMO的初步优化过程,具体可看:

关于SVM非线性相关的内容,我们留着下个星期来撕

这篇文章我们先来看看决策树的内容,决策树相对于SVM来讲要简单不少,也没有多么复杂的公式。我理解的决策树,简单来说就是通过已有的数据集训练出一个树形结构的模型,以便我们能够依据该模型对不知分类结果的数据进行预测。简单的决策树就有点类似于我们在学习数据结构时候的二叉排序树。当然了,决策树除了能够进行分类之外,还能进行回归,这里主要讨论的是分类问题。

关于决策树相关的内容,可能会肝两篇文章来介绍。第一篇主要是讲解决策树先关的基本知识,及其决策训练的过程,也就是我们的这篇文章,重在理论及推导,也重在理解。而第二篇文章写的主要内容是决策树的代码实战,而代码实战是在熟悉理论基础的前提之下来进行的,所以对于决策树相关的理论知识还是有必要了解的。可能的话,还会有第三篇,主要是关羽防止决策树过拟合的剪枝操作的内容。

一、什么是决策树

关于决策树的定义,李航——《统计学习方法》(第二版)这本书中是这样描述的:

分类决策树模型是一种描述对实例进行分类的树形结构,决策树由节点(node)和有向边(directed edge)组成。节点有两种类型:内部节点(iternal node)和叶节点(leaf node)。内部节点表示一个特征或属性,叶节点表示一个类。

上述提到的内部节点可以理解成样本的属性特征,而叶节点可以理解成样本的标签,而有向边可以理解成不同的属性特征结果。一般我们在绘制决策树的时候,内部节点用方框或长方形表示,而叶节点用圆形或椭圆表示。(注意:这个并不是绝对的,在不同资料中可能有不同的表示方法,比如《统计学习方法》一书中用圆表示内部节点,用方形表示叶子节点,而在《机器学习实战》一书中表示方式正好相反

枯燥的文字说明总是会降低读者的阅读欲望,下面我们不妨通过一个实际的例子来说明下,从而加强读者对决策树的理解。

比如说,形容女生美与丑的时候一般会存在多个指标,这个例子感觉有点危险,还是换个吧。

例子来源:李航——《统计学习方法》(第二版)

比如说,我们没Money用了,想要去银行贷款,这个时候银行就会根据你自己的个人附带特征来决定是否给你放款。假设这里的属性特征有四个,分别是年纪、是否工作、是否有房子、信用情况,这些属性特征就相当于是内部节点,标签(结果)是否放款相当于叶子节点,而不同属性特征的结果表示有向边,像年纪中有青年、中年、老年,信用情况有好、一般、非常好等表示不同的有向边。

对此,我们可以根据自己的感觉来手动绘制一个简单的决策树模型:

我们知道,上述决策树仅仅是我们自己手动来实现的,不一定能够运用于解决实际问题。而决策树的任务,则是根据已有的数据样本集训练得到这么一颗树形结构模型,以此来对未知分类的数据进行类别预测。对此,我们要向得到这么一颗尽可能理想的决策树,则不得不考虑以下几个问题:

  • 决策树的指标(属性特征)选择的顺序应该是怎样的的?哪个特征应当被优先考虑呢?
  • 如果构建出的决策树出现了过拟合问题,也就说我们的训练的时候还不错,但是一测试就GG,这个时候我们应当怎么解决呢?

本篇文章,主要内容是属性特征的优先选取问题。

二、属性特征的选择

对于属性特征的选择,我们应当优先选取对训练数据集具有明显分类能力的特征,这样可以提高我们决策树的学习效率。假如说一个属性特征的分类结果与随机分类基本没什么差别,则我们可以说这个属性特征基本是没有分类能力的。

比如说,我们这里有12个关于女生美与丑的数据样本,其中六个是丑女,另外六个是美女,六个丑女身高有三个是165cm、三个是185cm,而另外六个美女身高同样如此,这样的话,我们仅仅通过身高来对女生美貌的判断基本是没有分类能力的。(仅仅是个例子,不代表任何观点

所以,我们理想情况下决策树的生成理应是这样的:随着决策过程的不断进行,我们希望决策树的分支节点所包含的样本尽可能的属于同一类别(标签相同),也就是节点的“纯度”越来越高。

所以,决策树的关键技术在于属性特征的选择。对于属性特征的选择,我们通常有三个准则:信息增益、信息增益比(增益率)和基尼指数。

2.1 信息增益

上面提到了样本浓度,比如说我这里有10个女生,10个都是美女,那就说此时的样本浓度高,假如美女和丑女五五分,那这个时候的浓度就比较低了。这里的“浓度”表达的就是这个意思,它主要针对的是标签(结果)

而表示样本“浓度”的指标,最常用的就是“信息熵”了。假定当前样本集合\(D\)中第\(k\)类(总共\(n\)类)样本所占的比例为\(p_k\),则此时样本\(D\)的信息熵为:

\[Ent(D) = -\sum_{k=1}^np_klog_2(p_k) \tag{2-1}
\]

通过上述公式,我们可以知道10个美女(一个类别)的信息熵为

\[Ent(D)=-1 * log_21=0
\]

美女丑女五五分(两类)的信息熵为:

\[Ent(D) = -\frac{1}{2}log_2\frac{1}{2}-\frac{1}{2}log_2\frac{1}{2}=1
\]

通过上面信息熵的简单计算,我们可以知道,信息熵的值越小,则纯度越高。

既然我们已经了解了信息增益的计算公式及其所表达的意义,那么对于一个数据样本集,我们应当如何用代码来进行计算呢?下面我们来试试吧。

本次使用到的数据样本来自 李航——《统计学习方法》(第二版),数据是关于贷款申请的,具体如下:

那么现在我们来通过代码形式计算下这个数据样本集的信息熵吧:

首先创建一个establish_data方法来建立一个二维数组用于存储上述数据样本集的相关信息(关于属性特征所对于的值0,1,2之类的,大家可以参考上述表格对号入座,这里就不做过多解释了):

"""
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:创建训数据集
"""
def establish_data():
data = [[0, 0, 0, 0, 'N'], # 样本数据集相关信息,前面几项代表属性特征,最后一项表示是否放款
[0, 0, 0, 1, 'N'],
[0, 1, 0, 1, 'Y'],
[0, 1, 1, 0, 'Y'],
[0, 0, 0, 0, 'N'],
[1, 0, 0, 0, 'N'],
[1, 0, 0, 1, 'N'],
[1, 1, 1, 1, 'Y'],
[1, 0, 1, 2, 'Y'],
[1, 0, 1, 2, 'Y'],
[2, 0, 1, 2, 'Y'],
[2, 0, 1, 1, 'Y'],
[2, 1, 0, 1, 'Y'],
[2, 1, 0, 2, 'Y'],
[2, 0, 0, 0, 'N']]
return np.array(data)

随后,我们创建一个calc_information_entropy方法用于计算信息熵,计算过程的代码可结合上述的公式来看。另外,需要说一点的是,为了方便对放款结果进行分类,我们使用pandas包进行处理,关于pandas的使用,大伙可以参考文档,Taoye后期也会整理一份。当然了,不用pandas模块也能实现这个功能,有兴趣的读者可自行尝试,也不难。calc_information_entropy具体代码如下:

"""
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:计算信息熵
"""
def calc_information_entropy(data):
data_number, _ = data.shape
information_entropy = 0
for item in pd.DataFrame(data).groupby(_ - 1):
print(item[1])
proportion = item[1].shape[0] / data_number
information_entropy += - proportion * np.log2(proportion)
return information_entropy

我们运行上述代码,来看看具体的信息熵结果:

相比大家都了解了信息熵的概念,并能够手动计算样本集的信息熵了,现在我们再来把信息增益搬出来吧。

假设一个属性特征\(a\)有\(V\)个可能的取值\(\{a^1, a^2,.., a^V\}\),若使用\(a\)来对样本集\(D\)进行划分,这样的话就会产生\(V\)个分支节点,其中第\(v\)个 分支节点包含了\(D\)中所有在属性\(a\)上取值为\(a^V\)的样本,记为\(D^V\)。于是可计算出用属性特征\(a\)对样本集\(D\)进行划分所获得的“信息增益”(information gain)为:

\[Gain(D, a)=Ent(D)-\sum_{v=1}^V\frac{D^v}{D}Ent(D^v) \tag{2-2}
\]

以上是周志华——《机器学习》一书中对信息增益的相关说明。

枯燥的文字说明总是会降低读者的阅读欲望,上述符号也是有点多,我们不妨拿上面的贷款数据来进一步理解下上述信息增益的内容:

我们单独拿年龄这一个属性特征来计算其信息增益吧,其有青年、中年、老年三个可能的值,也就是说上述的\(a=年龄\),\(\{a^1,a^2,...,a^V\}=\{青年,中年,老年\}\),而数据样本集\(D\)为上述15个数据样本,由于年龄有三个可能的值,所以此时会产生三个分支,即\(V=3\)。之前我们已经计算得到\(Ent(D)=0.971\),现在我们只要计算出后一项\(\sum_{v=1}^V\frac{D^v}{D}Ent(D^v)\)的值即可得到该属性特征所对应的信息增益

通过数据,我们观察得到如下信息:

  • 对于年龄这个属性特征来讲,青年、中年、老年分别有5个。
  • 5个青年中有2个允许贷款,有三个不允许贷款;中年中有3个允许贷款,2个不允许贷款;老年中有4个允许贷款,有1个不允许贷款。

对此,我们可以计算:

\[\begin{aligned}
\sum_{v=1}^V\frac{D^v}{D}Ent(D^v) & = \frac{5}{15}(-\frac{2}{5}log_2\frac{2}{5}-\frac{3}{5}log_2\frac{3}{5})\\
& +\frac{5}{15}(-\frac{3}{5}log_2\frac{3}{5}-\frac{2}{5}log_2\frac{2}{5}) \\
& +\frac{5}{15}(-\frac{4}{5}log_2\frac{4}{5}-\frac{1}{5}log_2\frac{1}{5}) \\
& = 0.883
\end{aligned}
\]

对此,我们的计算处年龄这个属性特征所对应的信息增益值为:

\[Gain(D, 年龄) = 0.971-0.883=0.083
\]

我们可以把后一项的内容理解成条件概率。另外,信息增益越大,则其所对应的属性特征的分类能力也就越强,也就是我们应当优先选取的特征。

同理,我们可以计算出工作、房子、信用属性特征所对应的信息增益:

\[\begin{aligned}
& Gain(D, 工作)=0.324 \\
& Gain(D, 房子)=0.420 \\
& Gain(D, 信用)=0.363
\end{aligned}
\]

我们比较哥哥属性特征的信息增益值,可以发现房子这个属性特征最大,所以它应该是我们优先选择的属性特征。

了解了信息增益的计算及其意义,下面我们来通过代码计算一下(代码含义见注释):

import numpy as np
import pandas as pd np.__version__
pd.__version__ """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:创建训数据集
"""
def establish_data():
data = [[0, 0, 0, 0, 'N'], # 样本数据集相关信息,前面几项代表属性特征,最后一项表示是否放款
[0, 0, 0, 1, 'N'],
[0, 1, 0, 1, 'Y'],
[0, 1, 1, 0, 'Y'],
[0, 0, 0, 0, 'N'],
[1, 0, 0, 0, 'N'],
[1, 0, 0, 1, 'N'],
[1, 1, 1, 1, 'Y'],
[1, 0, 1, 2, 'Y'],
[1, 0, 1, 2, 'Y'],
[2, 0, 1, 2, 'Y'],
[2, 0, 1, 1, 'Y'],
[2, 1, 0, 1, 'Y'],
[2, 1, 0, 2, 'Y'],
[2, 0, 0, 0, 'N']]
return np.array(data) """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:计算信息熵
"""
def calc_information_entropy(data):
data_number, _ = data.shape
information_entropy = 0
for item in pd.DataFrame(data).groupby(_ - 1):
proportion = item[1].shape[0] / data_number
information_entropy += - proportion * np.log2(proportion)
return information_entropy """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:找出对应属性特征值的样本,比如找出所有年纪为青年的样本数据集
"""
def handle_data(data, axis, value):
result_data = list()
for item in data:
if item[axis] == value: result_data.append(item)
return result_data """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:计算最大的信息增益,并输出其所对应的特征索引
"""
def calc_information_gain(data):
feature_number = data.shape[1] - 1 # 属性特征的数量
base_entropy = calc_information_entropy(data) # 计算总体数据集的信息熵
max_information_gain, best_feature = 0.0, -1 # 初始化最大信息增益和对应的特征索引
for index in range(feature_number):
feat_list = [item[index] for item in data]
feat_set = set(feat_list)
new_entropy = 0.0
for set_item in feat_set: # 计算属性特征划分后的信息增益
sub_data = handle_data(data, index, set_item)
proportion = len(sub_data) / float(data.shape[0]) # 计算子集的比例
new_entropy += proportion * calc_information_entropy(np.array(sub_data))
temp_information_gain = base_entropy - new_entropy # 计算信息增益
print("第%d个属性特征所对应的的增益为%.3f" % (index + 1, temp_information_gain)) # 输出每个特征的信息增益
if (temp_information_gain > max_information_gain):
max_information_gain, best_feature = temp_information_gain, index # 更新信息增益,确定的最大的信息增益对应的索引
return best_feature if __name__ == "__main__":
data = establish_data()
print("属性特征对应的最大的信息增益对应的索引为:%d" % calc_information_gain(data))

运行上述代码,可见输出的各个属性特征的信息增益,以及最大信息增益对应的特征索引:

可以发现,和我们手动计算的如出一辙,所以此时我们应当优先选取索引为2的属性特征作为决策标准,也就是房子。

2.2 信息增益比(增益率)

我们使用信息增益作为选取特征指标的时候,存在偏向于选择取值较多的特征的问题。

比如我们将id作为上述数据集的一个分类属性,通过计算可以发现该信息增益最大,但实际上该id对类别不具有什么分类能力,所以这样得到的决策树不具有泛化能力,无法对新样本进行有效预测。

为了解决信息增益存在的这个问题,我们就引入了信息增益比(增益率)的概念,著名的C4.5算法就是用“增益率”来作为选取最优划分属性。增益率定义为:

\[Gain_ratio(D, a)=\frac{Gain(D, a)}{IV(a)} \tag{2-3}
\]
\[其中,IV(a)=-\sum_{v=1}^V\frac{|D^v|}{|D|}log_2\frac{|D^v|}{|D|} \tag{2-4}
\]

\(IV(a)\)称为\(a\)的“固有值”(intrinsic value)。通常\(a\)的取值数目越多,则\(IV(a)\)的值会越大。其中的\(a\)的取值比如说:上述的年纪有青年、中年、老年三种取值。

对于上述的贷款数据集来说,信用情况有一般、好和非常好三种,比例分为是\(\frac{5}{15}、\frac{6}{15}、\frac{4}{15}\)。毒刺,我们可以计算信用情况的“固有值”:

\[\begin{aligned}
IV(信用) & =-\sum_{v=1}^V\frac{|D^v|}{|D|}log_2\frac{|D^v|}{|D|} \\
& =-\frac{5}{15}log_2\frac{5}{15}-\frac{6}{15}log_2\frac{6}{15}-\frac{4}{15}log_2\frac{4}{15} \\
& = 1.566
\end{aligned}
\]

所以,对于信用属性来讲,其增益率为:

\[\begin{aligned}
Gain\_ratio(D, 信用) & =\frac{Gain(D, 信用)}{IV(信用)} \\
& = \frac{0.363}{1.566} \\
& = 0.232
\end{aligned}
\]

同理,我们可以计算出其他属性特征的增益率:

\[\begin{aligned}
Gain\_ratio(D, 年龄) & =0.052 \\
Gain\_ratio(D, 工作) & =0.352 \\
Gain\_ratio(D, 房子) & =0.433 \\
\end{aligned}
\]

计算增益率的具体代码可参考如下:

"""
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:计算增益率
"""
def calc_gain_ratio(data):
feature_number = data.shape[1] - 1 # 属性特征的数量
base_entropy = calc_information_entropy(data) # 计算总体数据集的信息熵
for index in range(feature_number):
feat_list = [item[index] for item in data]
feat_set = set(feat_list)
new_entropy, iv = 0.0, 0.0
for set_item in feat_set: # 计算属性特征划分后的信息增益
sub_data = handle_data(data, index, set_item)
proportion = len(sub_data) / float(data.shape[0]) # 计算子集的比例
new_entropy += proportion * calc_information_entropy(np.array(sub_data))
iv += -proportion * np.log2(proportion)
temp_information_gain = base_entropy - new_entropy # 计算信息增益
gain_ratio = temp_information_gain / iv
print("第%d个属性特征所对应的增益率为%.3f,信息增益为%.3f" % (index + 1, gain_ratio, temp_information_gain)) # 输出每个特征的信息增益

运行结果如下:

在C4.5算法中,并不是直接单一的使用增益率来对属性特征的选取进行决策,而是先在信息增益中选取高于平均水平的属性作为候选,然后从候选中选取增益率最高的。

关于C4.5算法,我们后期会讲到。

2.3 基尼指数

基尼指数是另外一种选取属性的指标。

前面我们提到了,信息熵是描述数据样本纯度一个标准,而在基尼指数中的基尼值同样可以体现数据样本的纯度。数据样本集\(D\)的基尼值可以用\(Gini(D)\)来表示(其中\(k\)表示有\(k\)个标签结果):

\[Gini(D)=1-\sum_{k=1}^{|y|}p_k^2 \tag{2-5}
\]

基尼值\(Gini(D)\)越小,说明数据样本纯度越高。而属性\(a\)对应的基尼指数\(Gini\_index(D,a)\)可以定义为:

\[Gini\_index(D, a)=\sum_{v=1}^V\frac{|D^v|}{|D|}Gini(D^v) \tag{2-6}
\]

我们同样来分别计算下上述贷款数据集的基尼指数。

对于信用情况这一属性特征来讲,其基尼指数的手动计算过程如下所示:

\[\begin{aligned}
Gini\_index(D, 信用) & = \sum_{v=1}^{V}\frac{|D^v|}{|D|}Gini(D^v) \\
& = \frac{5}{15}(1-(\frac{4}{5})^2 - (\frac{1}{5})^2)+\frac{6}{15}(1-(\frac{2}{6})^2 - (\frac{4}{6})^2)+\frac{4}{15}(1-(\frac{4}{4})^2 - (\frac{0}{4})^2) \\
& =
\end{aligned}
\]

对于其他属性的基尼指数,读者可自行根据上述过程进行计算(真的很简单)。关于基尼指数的计算代码,可参考如下:

"""
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:计算基尼指数
"""
def calc_gini_index(data):
feature_number = data.shape[1] - 1 # 属性特征的数量
base_entropy = calc_information_entropy(data) # 计算总体数据集的信息熵
for index in range(feature_number):
feat_list = [item[index] for item in data]
feat_set = set(feat_list)
new_entropy, iv, gini_index = 0.0, 0.0, 0.0
for set_item in feat_set: # 计算属性特征划分后的信息增益
sub_data = handle_data(data, index, set_item)
temp_df = pd.DataFrame(sub_data)
yes_proportion = temp_df[temp_df[temp_df.shape[1]-1] == "Y"].shape[0] / len(sub_data)
gini_value = 1 - (yes_proportion ** 2) - ((1- yes_proportion) ** 2)
proportion = len(sub_data) / float(data.shape[0]) # 计算子集的比例
new_entropy += proportion * calc_information_entropy(np.array(sub_data))
iv += -proportion * np.log2(proportion)
gini_index += gini_value * proportion # 计算基尼指数
temp_information_gain = base_entropy - new_entropy # 计算信息增益
gain_ratio = temp_information_gain / iv
print("第%d个属性特征所对应的信息增益为%.3f,增益率为%.3f, 基尼指数为%.3f" % (index + 1, temp_information_gain, gain_ratio, gini_index))

运行结果:

以上就是基尼指数的计算及其相关代码,一般来讲,基尼指数越小就优先被划分。

上述内容的完整代码如下:

import numpy as np
import pandas as pd np.__version__
pd.__version__ """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:创建训数据集
"""
def establish_data():
data = [[0, 0, 0, 0, 'N'], # 样本数据集相关信息,前面几项代表属性特征,最后一项表示是否放款
[0, 0, 0, 1, 'N'],
[0, 1, 0, 1, 'Y'],
[0, 1, 1, 0, 'Y'],
[0, 0, 0, 0, 'N'],
[1, 0, 0, 0, 'N'],
[1, 0, 0, 1, 'N'],
[1, 1, 1, 1, 'Y'],
[1, 0, 1, 2, 'Y'],
[1, 0, 1, 2, 'Y'],
[2, 0, 1, 2, 'Y'],
[2, 0, 1, 1, 'Y'],
[2, 1, 0, 1, 'Y'],
[2, 1, 0, 2, 'Y'],
[2, 0, 0, 0, 'N']]
return np.array(data) """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:计算信息熵
"""
def calc_information_entropy(data):
data_number, _ = data.shape
information_entropy = 0
for item in pd.DataFrame(data).groupby(_ - 1):
proportion = item[1].shape[0] / data_number
information_entropy += - proportion * np.log2(proportion)
return information_entropy """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:找出对应属性特征值的样本,比如找出所有年纪为青年的样本数据集
"""
def handle_data(data, axis, value):
result_data = list()
for item in data:
if item[axis] == value: result_data.append(item)
return result_data """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:计算最大的信息增益,并输出其所对应的特征索引
"""
def calc_information_gain(data):
feature_number = data.shape[1] - 1 # 属性特征的数量
base_entropy = calc_information_entropy(data) # 计算总体数据集的信息熵
max_information_gain, best_feature = 0.0, -1 # 初始化最大信息增益和对应的特征索引
for index in range(feature_number):
feat_list = [item[index] for item in data]
feat_set = set(feat_list)
new_entropy = 0.0
for set_item in feat_set: # 计算属性特征划分后的信息增益
sub_data = handle_data(data, index, set_item)
proportion = len(sub_data) / float(data.shape[0]) # 计算子集的比例
new_entropy += proportion * calc_information_entropy(np.array(sub_data))
temp_information_gain = base_entropy - new_entropy # 计算信息增益
print("第%d个属性特征所对应的的增益为%.3f" % (index + 1, temp_information_gain)) # 输出每个特征的信息增益
if (temp_information_gain > max_information_gain):
max_information_gain, best_feature = temp_information_gain, index # 更新信息增益,确定的最大的信息增益对应的索引
return best_feature """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:计算增益率
"""
def calc_gain_ratio(data):
feature_number = data.shape[1] - 1 # 属性特征的数量
base_entropy = calc_information_entropy(data) # 计算总体数据集的信息熵
for index in range(feature_number):
feat_list = [item[index] for item in data]
feat_set = set(feat_list)
new_entropy, iv = 0.0, 0.0
for set_item in feat_set: # 计算属性特征划分后的信息增益
sub_data = handle_data(data, index, set_item)
proportion = len(sub_data) / float(data.shape[0]) # 计算子集的比例
new_entropy += proportion * calc_information_entropy(np.array(sub_data))
iv += -proportion * np.log2(proportion)
temp_information_gain = base_entropy - new_entropy # 计算信息增益
gain_ratio = temp_information_gain / iv
print("第%d个属性特征所对应的增益率为%.3f,信息增益为%.3f" % (index + 1, gain_ratio, temp_information_gain)) # 输出每个特征的信息增益 """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain:计算基尼指数
"""
def calc_gini_index(data):
feature_number = data.shape[1] - 1 # 属性特征的数量
base_entropy = calc_information_entropy(data) # 计算总体数据集的信息熵
for index in range(feature_number):
feat_list = [item[index] for item in data]
feat_set = set(feat_list)
new_entropy, iv, gini_index = 0.0, 0.0, 0.0
for set_item in feat_set: # 计算属性特征划分后的信息增益
sub_data = handle_data(data, index, set_item)
temp_df = pd.DataFrame(sub_data)
yes_proportion = temp_df[temp_df[temp_df.shape[1]-1] == "Y"].shape[0] / len(sub_data)
gini_value = 1 - (yes_proportion ** 2) - ((1- yes_proportion) ** 2)
proportion = len(sub_data) / float(data.shape[0]) # 计算子集的比例
new_entropy += proportion * calc_information_entropy(np.array(sub_data))
iv += -proportion * np.log2(proportion)
gini_index += gini_value * proportion
temp_information_gain = base_entropy - new_entropy # 计算信息增益
gain_ratio = temp_information_gain / iv
print("第%d个属性特征所对应的信息增益为%.3f,增益率为%.3f, 基尼指数为%.3f" % (index + 1, temp_information_gain, gain_ratio, gini_index)) if __name__ == "__main__":
data = establish_data()
calc_gini_index(data)

优先选取属性特征的指标主要有三个,分别是信息增益、增益率、基尼指数。对上述内容做个简单的总结吧:

  • 属性特征的信息增益越高,按道理来讲应当被优先选取,常用于\(ID3\)算法
  • 属性特征的增益率越高,按道理来讲应当被优先选取,常用与\(C4.5\)算法
  • 属性特征的尼基指数低,按道理来讲应当被优先选取,常用于\(CART\)算法

本文主要是决策树的理论部分内容,介绍了什么决策树,以及生成决策树时所需要优先选取的三种决策标准。有学习的过SVM,或阅读过Taoye之前写的几篇SVM内容的文章可以发现,决策树相对于SVM来讲要简单很多,没有太多且复杂的公式推导。关于决策树的其他内容,比如决策树的生成、可视化、剪枝等,我们放在后面几篇文章来写。

我是Taoye,爱专研,爱分享,热衷于各种技术,学习之余喜欢下象棋、听音乐、聊动漫,希望借此一亩三分地记录自己的成长过程以及生活点滴,也希望能结实更多志同道合的圈内朋友,更多内容欢迎来访微信公主号:玩世不恭的Coder

《Machine Learning in Action》—— Taoye给你讲讲决策树到底是支什么“鬼”的更多相关文章

  1. 机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试

    机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理.源码解析及测试 关键字:决策树.python.源码解析.测试作者:米仓山下时间:2018-10-2 ...

  2. 《Machine Learning in Action》—— Taoye给你讲讲Logistic回归是咋回事

    在手撕机器学习系列文章的上一篇,我们详细讲解了线性回归的问题,并且最后通过梯度下降算法拟合了一条直线,从而使得这条直线尽可能的切合数据样本集,已到达模型损失值最小的目的. 在本篇文章中,我们主要是手撕 ...

  3. 《Machine Learning in Action》—— 小朋友,快来玩啊,决策树呦

    <Machine Learning in Action>-- 小朋友,快来玩啊,决策树呦 在上篇文章中,<Machine Learning in Action>-- Taoye ...

  4. 《Machine Learning in Action》—— 懂的都懂,不懂的也能懂。非线性支持向量机

    说在前面:前几天,公众号不是给大家推送了第二篇关于决策树的文章嘛.阅读过的读者应该会发现,在最后排版已经有点乱套了.真的很抱歉,也不知道咋回事,到了后期Markdown格式文件的内容就解析出现问题了, ...

  5. 《Machine Learning in Action》—— 白话贝叶斯,“恰瓜群众”应该恰好瓜还是恰坏瓜

    <Machine Learning in Action>-- 白话贝叶斯,"恰瓜群众"应该恰好瓜还是恰坏瓜 概率论,可以说是在机器学习当中扮演了一个非常重要的角色了.T ...

  6. 《Machine Learning in Action》—— 浅谈线性回归的那些事

    <Machine Learning in Action>-- 浅谈线性回归的那些事 手撕机器学习算法系列文章已经肝了不少,自我感觉质量都挺不错的.目前已经更新了支持向量机SVM.决策树.K ...

  7. 《Machine Learning in Action》—— 剖析支持向量机,单手狂撕线性SVM

    <Machine Learning in Action>-- 剖析支持向量机,单手狂撕线性SVM 前面在写NumPy文章的结尾处也有提到,本来是打算按照<机器学习实战 / Machi ...

  8. 《Machine Learning in Action》—— 剖析支持向量机,优化SMO

    <Machine Learning in Action>-- 剖析支持向量机,优化SMO 薄雾浓云愁永昼,瑞脑销金兽. 愁的很,上次不是更新了一篇关于支持向量机的文章嘛,<Machi ...

  9. K近邻 Python实现 机器学习实战(Machine Learning in Action)

    算法原理 K近邻是机器学习中常见的分类方法之间,也是相对最简单的一种分类方法,属于监督学习范畴.其实K近邻并没有显式的学习过程,它的学习过程就是测试过程.K近邻思想很简单:先给你一个训练数据集D,包括 ...

随机推荐

  1. spring boot:方法中使用try...catch导致@Transactional事务无效的解决(spring boot 2.3.4)

    一,方法中使用try...catch导致@Transactional事务无效的解决方法 1,问题的描述: 如果一个方法添加了@Transactional注解声明事务, 而方法内又使用了try catc ...

  2. package wang/test is not in GOROOT (/usr/local/go/src/wang/test)

    如果要用 gopath模式 引入包 从src目录下开始引入 需要关闭 go mod 模式 export GO111MODULE=off 如果使用go mod 模式 export GO111MODULE ...

  3. linux(centos8):prometheus使用mtail监控错误日志

    一,mtail的用途? mtail :从应用程序日志中提取指标以导出到时间序列数据库或时间序列计算器 它是一个google开发的日志提取工具,用途就是: 实时读取应用程序的日志. 再通过自己编写的脚本 ...

  4. centos8上配置openssh的安全

    一,openssh服务版本号的查看 1,查看当前sshd的版本号 : [root@yjweb ~]# sshd --help unknown option -- - OpenSSH_7.8p1, Op ...

  5. c# 误区系列(二)

    前言 继续整理误区系列,可能会对刚入门的新手有些帮助,然后希望有错误的地方可以指出. 正文 关于泛型方法的确定 class Person<T> { public void add(T a) ...

  6. 企业级RPC框架zRPC

    近期比较火的开源项目go-zero是一个集成了各种工程实践的包含了Web和RPC协议的功能完善的微服务框架,今天我们就一起来分析一下其中的RPC部分zRPC. zRPC底层依赖gRPC,内置了服务注册 ...

  7. 记录Spring Boot 2.3.4.RELEASE版注解方式实现AOP和通知的执行顺序

    1.advice 按照以下的顺序执行 输出结果:(正常和异常) 说明:Spring boot 2.3.4.RELEASE 版本使用的AOP是spring-aop-5.2.9.RELEASE,AOP的通 ...

  8. net core 微服务框架 Viper 调用链路追踪

    1.Viper是什么? Viper 是.NET平台下的Anno微服务框架的一个示例项目.入门简单.安全.稳定.高可用.全平台可监控.底层通讯可以随意切换thrift grpc. 自带服务发现.调用链追 ...

  9. Java基础之类型转换总结篇

    Java中,经常可以遇到类型转换的场景,从变量的定义到复制.数值变量的计算到方法的参数传递.基类与派生类间的造型等,随处可见类型转换的身影.Java中的类型转换在Java编码中具有重要的作用.    ...

  10. Jenkins 凭证管理 - 看这一篇就够了~

    目录 Credential 类型 Credential 安全 Credential 创建 Credential ID 定义 Credential 使用 Credential 相关插件 最佳实践 许多三 ...