《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. 测试-python相关

    python基础 一行代码实现1~100累加,不使用for循环 方式一: sum(range(1,101)) 方式二: 1 from functools import reduce 2 reduce( ...

  2. ▶ 0001 No application 'E:\www\go\blog' found in your GOPATH

    go mod 配置 beego 首先cmd bee new blog go mod init 然后复制到任意目录 bee run 就会报错, 要退出该目录,进入上级目录 bee run blog 才行

  3. oracle统计同一字段0和1

    SELECT 班级表.班级编号,班级表.班级名称,SUM(DECODE(性别, '1', 1)) 女生人数,SUM(DECODE(性别, '0', 1)) 男生人数FROM 学生表, 班级表WHERE ...

  4. Harbor 安装教程

    Harbor 安装教程 一. CentOS设置 1. 更换阿里源 curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com ...

  5. dhtmlxSpreadSheet开源电子表格小部件创建教程

    dhtmlxSpreadSheet是用纯JavaScript编写的开源电子表格小部件,可让您快速在网页上添加类似于Excel的可编辑数据表.高度可定制的JavaScript电子表格组件,具有优雅的Ma ...

  6. java安全编码指南之:ThreadPool的使用

    目录 简介 java自带的线程池 提交给线程池的线程要是可以被中断的 正确处理线程池中线程的异常 线程池中使用ThreadLocal一定要注意清理 简介 在java中,除了单个使用Thread之外,我 ...

  7. H5移动端实现图片上传

    转至 :https://blog.csdn.net/qq_37610423/article/details/84319410 效果图: 我在用这个的时候发现博主少写了一些东西,导致功能无法实现,所以我 ...

  8. collection v1.3.1升级全记录

    collection v1.3.1升级全记录 项目地址: https://github.com/jianfengye/collection 欢迎star. collection 手册地址: http: ...

  9. 渗透测试之GoogleHack

    GoogleHack 1,介绍: 使用google等搜索引擎对某些特定的网络主机漏洞(一般是服务器上的脚本漏洞)进行搜索,都能达到快速找到1漏洞的目的,然而,google相对百度讲,没有广告,搜索引擎 ...

  10. 如何实现一个FormData

    一.前言 最近项目中遇到一个问题,我们需要在cocos项目里去上传音频文件,而cocos原生环境和平时我们开发所在的浏览器环境和Node环境有很多差异,而cocos环境只提供了基础类,没有提供Form ...