机器学习(3) - 决策树

决策树的思想比较简单,就是对于各个特征做一个划分,然后按一定的顺序判断。直观上的理解是一个样本依次经过一个树的判断,然后被划分到各个叶子节点上,如果是分类问题,那么叶子节点上的样本属于同一个类别,如果是属于回归问题,那么把叶子节点所有样本的值进行平均就得到了回归的值。

【决策树面临的两个核心问题】

(1) 怎么在每个判断节点选择特征

(2) 怎么在每个判断节点怎么选择特征的阈值来进行一个划分

为了解决以上的问题,有很多算法,基于熵,基于基尼系数(Cart),或者ID3 或者ID4.5, 基于信息增益。

 

【数学知识】

(1) 自信息量

参考这句话: I(ai)表示一个消息ai出现后所带来的信息量,用其概率的负对数来表示,即I(ai)=-log2p(ai),因此I(ai)是非负值,并且是概率p(ai)的单调递减函数。用公式表达就是下面的这个式子

I(x) = -log(p(x)) 

翻译一下这个公式,表达的意思是如果随机变量x发生,并且以概率P(x)发生,那么这个事件的发生带来信息量为I(x),可以发现如果概率越小那么能带来的信息量就越大。

这里自信息量不能代表信源的整体不确定度,或者随机变量的整体不确定度,只能表示是一个消息或者随机变量取某一个值的不确定度,不能反映整体情况,为了反映整体情况,需要引入熵。

(2) 熵,熵的解释是: 随机变量的不确定性。

熵是对随机变量自信息取期望得到。代表的是平均不确定性。熵是对平均不确定性的度量,熵是随机变量不确定性的度量,不确定性越大,熵值越大;若随机变量退化成定值,熵为0。该不确定性度量的本质即为信息量的期望。其中均匀分布是“最不确定”的分布。同时信息熵也反应了一个系统的有序化程度,一个系统越是有序,那么它的信息熵就越低,反之越高。

随机变量X的熵计算公式是:


熵越大,则随机变量的不确定性越大

样本与随机变量之间转换或对应的一点思考:正常情况下,如果一个组样本,样本没有label的话,比如无监督学习,那么我们会认为每个样本是一个随机变量的采样,样本通常是被认为一个多维随机变量,每个样本出现的概率是P(x1,x2,...,xn), 随机变量可能是离散的也可能是连续的

在决策树这里,当样本有标签考虑标签值的时候,或者只考虑样本某一个维度特征时,这时候所谓的随机变量就和上面的意义不一样,这里的随机变量的取值范围有限,或者说从多维的随机变量变成了单维随机变量(这里确切的说是离散单维随机变量),在离散的每一个取值上,都包含了很多个样本。这些样本本身在其他的维度上可能差异挺大的。通过一个例子理解。比如一组样本有三类数据,每个类别的占比是 {1/3, 1/3, 1/3}, 那么这里的随机变量实际上取值是3个类别,每个类别的概率都是1/3。 这里又有一个随机变量概率到样本分布之间的转换。这组数据的不确定性或者熵是实际上是 -Σ(1/3)Log(1/3)。

在随机变量只能取0或1是,设置随机变量1个种取值的概率值,P(X=1)=p因为就两种取值可能,所以可以做一个二维的图,横轴是P的取值范围0~1,纵轴是随机变量整体的熵H(x), 本来这里是要画一个3维的图,两个x轴是随机变量在不同类别上的取值范围,纵轴是随机变量整体的熵H(x)。由下图可以发现,当随机变量P(x=0)=p(x=1)=0.5的时候,整体随机变量不确定性最大,熵最大。或者熵是整体系统的不确定性最大。



【构建决策树的方法】

1和2方法比较直观,就是在每次判断的节点,对所有的特征进行遍历,对所有划分的可能进行遍历(两个点之间的空隙),计算按这样划分以后,样本在各个叶子节点上的熵,然后对于遍历的结果找出两个节点熵总和最小的划分。

1: 基于熵- Entropy

from collections import Counter
from math import log

#对于d号维度,按照value值进行划分
#返回划分好以后的数据和label值
def split(X, y, d, value):
    index_a = (X[:,d] <= value)
    index_b = (X[:,d] > value)
    return X[index_a], X[index_b], y[index_a], y[index_b]

#这个函数输入的是样本数据label值的集合,记下label的具体取值和各个取值下的个数
def entropy(y):
    counter = Counter(y)#统计出样本label集合在各个值出现的次数
    res = 0.0
    for num in counter.values():#对各个label值进行遍历
        p = num / len(y)
        res += -p * log(p)
    return res

#这个函数的功能是输入一组样本,对这组样本的特征进行一次划分
#
def try_split(X, y):#
    
    best_entropy = float('inf')
    best_d, best_v = -1, -1
    #对列进行遍历,对各个特征进行遍历
    for d in range(X.shape[1]):
        #sorted_index返回的是排序以后,原始数据排序所得的index
        sorted_index = np.argsort(X[:,d])#根据特征的值进行排序
        #对各个数据行,样本进行遍历
        for i in range(1, len(X)):#对所有样本进行遍历 -- 这里len(X)x是一个二维的数据,len返回的0号index的长度,也即元素个数
            #如果当前i号样本和i-1号样本,在d号维度上不相等
            if X[sorted_index[i], d] != X[sorted_index[i-1], d]:
                #计算出划分的值
                v = (X[sorted_index[i], d] + X[sorted_index[i-1], d])/2
                #按照这个划分
                X_l, X_r, y_l, y_r = split(X, y, d, v)
                #计算两个子树的熵之和
                e = entropy(y_l) + entropy(y_r)#函数传入的参数是数据的label集合
                if e < best_entropy:
                    best_entropy, best_d, best_v = e, d, v
                
    return best_entropy, best_d, best_v

这里的try_split函数是对数据的一次划分,相对于决策树中的一个判断节点。判断并且划分完毕以后,左右子树的熵之和要小于原始数据的熵,如果一直划分,可以让子树的熵为0,相当于子节点只有一种类别的样本。

根据统计学习方法这本书,在计算下面的这个值时,还考虑了y_1与y_2的个数差异,参考<统计学习方法>书第70页公式5.25

e = entropy(y_l) + entropy(y_r)


2:基于基尼系数

基尼系数也是衡量分布是否平衡的指标,或者是描述随机变量不确定性的指标。分布越不平衡,随机变量不确定性越小。则基尼系数越小。分布越平衡,随机变量不确定性越大,则基尼系数越大。



基尼系数计算公式

#基尼系数也是衡量概率分布是否均衡的指标,越不均衡,基尼系数越小,越均衡基尼系数越大
#概率分布越不均衡,则熵越大,
def gini(y):
    counter = Counter(y)
    res = 1.0
    for num in counter.values():
        p = num / len(y)
        res -= p**2
    return res

同样在划分进行特征选择和阈值判断的时候和基于熵的方法区别是一个计算被划分样本的熵,一个计算被划分样本的基尼系数

                X_l, X_r, y_l, y_r = split(X, y, d, v)
                g = gini(y_l) + gini(y_r)


3:Cart算法

Cart = classification and regression tree,总结一下特征

(1)Cart算法可以用在分类也可以用在回归,回归树用平方误差最小化准则,对分类树用基尼系数最小化准则,进行特征选择,生成二叉树。

(2)是二叉树结构,内部特征节点特征的取值为 “是”和“否”,左分支是取值为 "是"的分支,右分支是取值为 “否”的分支。这样的决策树等价于递归的二分每个特征。决策树的生成就是递归的构建二叉决策树的过程

(3) 给定输入随机变量X的条件下输出随机变量Y的条件概率分布的学习方法 -- 这句话很抽象。
(4) 算法停止的条件是结点中的样本个数小于预定阈值,或样本集的基尼指数小于预定阈值(这时候样本都是同一类别),或者没有更多特征。

3.1 Cart分类Tree

分类tree的话和1和2展示的代码一样,用二叉树完成分类,采用gini系数。

3.2 Cart回归Tree

https://zhuanlan.zhihu.com/p/36108972 这个人这里举的例子好像和<统计学习方法>中讲的不一样,但是这里有一个问题是对一个特征反复划分,但是好像没有对二叉树输出的两个子样本集合进行进一步的划分,有点奇怪

另外统计学习方法书上所描述的公式还是比较直观。69页。实际上就是对这个叶子结点所有样本的y值取平均做为预测的输出。在选择特征和划分阈值时,是统计各自两个叶子结点内,样本y值的方差,选一个方差最小的划分。


4:基于信息增益ID3, ID4.5

ID3和ID4.5类似,ID4.5是做了一个归一化的动作。总结一下ID3的特点

(1) 只适合属性特征,不适合连续特征,对于特征A的划分不是二叉树,是有多少属性做多少判断输出分支,这里的属性是指特征的离散取值。ID3算法是默认操作是: 根据特征A的取值,将样本集合D划分为n个子集,D1,D2,...,Dn。所以ID3算法和Cart算法不一样,ID3算法只需要选择特征,而不需要考虑怎么去划分特征空间。

(2) 选择特征的时候是采用的信息增益,信息增益最大的特征为划分特征。信息增益的公式是:


这部分要把<统计学习方法>书的例子弄过来

给定训练数据集D和特征A, 经验熵H(D)表示对数据集D进行分类的不确定性。而经验条件熵H(D|A)表示在特征A给定的条件下对数据集D进行分类的步确定性,那么他们的差,即信息增益,表示由于特征A而使得对数据集D的分类不确定性减少的程度。显然,对于数据集D而言,信息增益依赖于特征,不同的特征往往具有不同的信息增益。(统计学习方法原话)

总结一下,感觉所谓的经验熵是对于本身的数据做统计,分析现有数据。只考虑数据的类别分布,经验条件熵是出了类别以外,引入一个特征,在特征的划分之下,在进行类别的划分,这样的话,万一某一个特征的划分,是完全属于一个类别的话,那么很有可能会降低类别的不确定性,“至于怎么就能降低类别的步确定性,我感觉不特征进行标记就行,标记一种特征完全属于一种类别”。总而言之,就是特征的引入,可以使得类别的划分的不确定性降低。那么算出条件熵以后,做一个减法,就能获得信息增益。


【Sklearn库】

在Sklearn中, 有两个函数

(1)DecisionTreeClassifier() -- 用来分类

(2)DecisionTreeRegressor() -- 用来回归


【决策树的裁剪】

后续再看


【参考连接】

1: 代码 - https://github.com/liuyubobobo/Play-with-Machine-Learning-Algorithms

2: <<统计学习方法>>,决策树部分

这里需要写一个信息量,熵,相对熵,KL散度等等的总结性文章

https://blog.csdn.net/ggwcr/article/details/77964184

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值