信息论基础(熵 联合熵 条件熵 信息增益 基尼不纯度)
熵:信息熵的概念来描述信源的不确定度。信息量的度量就等于不确定性的多少。比如,有人说广东下雪了。对于这句话,我们是十分不确定的。因为广东几十年来下雪的次数寥寥无几。为了搞清楚,我们就要去看天气预报,新闻,询问在广东的朋友,而这就需要大量的信息,信息熵很高。再比如,中国男足进军2022年卡塔尔世界杯决赛圈。对于这句话,因为确定性很高,几乎不需要引入信息,信息熵很低
联合熵:联合熵就是度量一个联合分布的随机系统的不确定度,下面给出两个随机变量的联合熵的定义:
分布为 p(x,y)p(x,y) 的一对随机变量 (X,Y)(X,Y) ,其联合熵定义为:
条件熵条件熵 H(Y|X) 表示在已知随机变量 X 的条件下随机变量 Y 的不确定性。条件熵 H(Y|X) 定义为 X 给定条件下 Y 的条件概率分布的熵对 X 的数学期望
相对熵 (Relative entropy),也称KL散度 (Kullback–Leibler divergence):
p(x)、q(x) 是 离散随机变量 X 中取值的两个概率分布,则 p 对 q 的相对熵是:
性质:
1、如果 p(x) 和 q(x) 两个分布相同,那么相对熵等于0
2、DKL(p||q)≠DKL(q||p) ,相对熵具有不对称性。大家可以举个简单例子算一下。
3、DKL(p||q)≥0 证明如下(利用Jensen不等式https://en.wikipedia.org/wiki/Jensen%27s_inequality):
总结:相对熵可以用来衡量两个概率分布之间的差异,上面公式的意义就是求 p 与 q 之间的对数差在 p 上的期望值。
交叉熵 (Cross entropy)
如果使用非真实分布 q(x) 来表示来自真实分布 p(x) 的平均编码长度,则是:
(因为用 q(x) 来编码的样本来自于分布 q(x) ,所以 H(p,q) 中的概率是 p(x))。此时就将 H(p,q) 称之为交叉熵。举个例子。考虑一个随机变量 x,真实分布
在机器学习中,我们希望在训练数据上模型学到的分布 P(model) 和真实数据的分布 P(real) 越接近越好,所以我们可以使其相对熵最小。但是我们没有真实数据的分布,所以只能希望模型学到的分布 P(model) 和训练数据的分布 P(train) 尽量相同。假设训练数据是从总体中独立同分布采样的,那么我们可以通过最小化训练数据的经验误差来降低模型的泛化误差。即:
希望学到的模型的分布和真实分布一致,
但是真实分布不可知,假设训练数据是从真实数据中独立同分布采样的,
因此,我们希望学到的模型分布至少和训练数据的分布一致,
根据之前的描述,最小化训练数据上的分布 P(train) 与最小化模型分布 P(model) 的差异等价于最小化相对熵,即 DKL(P(train)||P(model))。此时, P(train) 就是DKL(p||q) 中的 p,即真实分布,P(model) 就是 q。又因为训练数据的分布 p 是给定的,所以求 DKL(p||q) 等价于求 H(p,q)。得证,交叉熵可以用来计算学习模型分布与训练分布之间的差异。交叉熵广泛用于逻辑回归的Sigmoid和Softmax函数中作为损失函数使用。
信息熵是传输一个随机变量状态值所需的比特位下界(最短平均编码长度)。
相对熵是指用 q 来表示分布 p 额外需要的编码长度。
交叉熵是指用分布 q 来表示本来表示分布 p 的平均编码长度。
**信息增益:**信息增益就是熵和特征条件熵的差
g(D,A)=H(D)-H(D|A)
对一个确定的数据集来说,H(D)是确定的,那H(D|A)在A特征一定的情况下,随机变量的不确定性越小,信息增益越大,这个特征的表现就越好
基尼不纯度:
从一个数据集中随机选取子项,度量其被错误的划分到其他组里的概率。(书上解释)
一个随机事件变成它的对立事件的概率(简单理解)
一个随机事件X ,P(X=0)= 0.5 ,P(X=1)=0.5
那么基尼不纯度就为 P(X=0)*(1 - P(X=0)) + P(X=1)*(1 - P(X=1)) = 0.5
一个随机事件Y ,P(Y=0)= 0.1 ,P(Y=1)=0.9
那么基尼不纯度就为P(Y=0)*(1 - P(Y=0)) + P(Y=1)*(1 -P(Y=1)) = 0.18
很明显 X比Y更混乱,因为两个都为0.5 很难判断哪个发生。而Y就确定得多,Y=1发生的概率很大。而基尼不纯度也就越小。
结论:
(1)基尼不纯度可以作为 衡量系统混乱程度的 标准;
(2)基尼不纯度越小,纯度越高,集合的有序程度越高,分类的效果越好;
(3)基尼不纯度为 0 时,表示集合类别一致;
(4)在决策树中,比较基尼不纯度的大小可以选择更好的决策条件(子节点)。
决策树的不同分类算法(ID3算法、C4.5、CART分类树)的原理及应用场景
https://blog.csdn.net/weixin_39750084/article/details/83449866[决策树算法原理详解(ID3、C4.5、CART树)]
回归树原理
决策树实际上是将空间用超平面进行划分的一种方法,每次分割的时候,都将当前的空间一分为二, 这样使得每一个叶子节点都是在空间中的一个不相交的区域,在进行决策的时候,会根据输入样本每一维feature的值,一步一步往下,最后使得样本落入N个区域中的一个(假设有N个叶子节点),如下图所示。
既然是决策树,那么必然会存在以下两个核心问题:如何选择划分点?如何决定叶节点的输出值?
一个回归树对应着输入空间(即特征空间)的一个划分以及在划分单元上的输出值。分类树中,我们采用信息论中的方法,通过计算选择最佳划分点。而在回归树中,采用的是启发式的方法。假如我们有n个特征,每个特征有si(i∈(1,n))si(i∈(1,n))个取值,那我们遍历所有特征,尝试该特征所有取值,对空间进行划分,直到取到特征j的取值s,使得损失函数最小,这样就得到了一个划分点。描述该过程的公式如下:
决策树防止过拟合手段
剪枝:提前停止树的增长或者对已经生成的树按照一定的规则进行后剪枝。
剪枝的方法
剪枝是一个简化过拟合决策树的过程。有两种常用的剪枝方法:
(1)先剪枝(prepruning):通过提前停止树的构建而对树“剪枝”,一旦停止,节点就成为树叶。该树叶可以持有子集元组中最频繁的类;
先剪枝的方法
有多种不同的方式可以让决策树停止生长,下面介绍几种停止决策树生长的方法:
限制决策树的高度和叶子结点处样本的数目
1.定义一个高度,当决策树达到该高度时就可以停止决策树的生长,这是一种最为简单的方法;
2.达到某个结点的实例具有相同的特征向量,即使这些实例不属于同一类,也可以停止决策树的生长。这种方法对于处理数据中的数据冲突问题非常有效;
3.定义一个阈值,当达到某个结点的实例个数小于该阈值时就可以停止决策树的生长;
4.定义一个阈值,通过计算每次扩张对系统性能的增益,并比较增益值与该阈值的大小来决定是否停止决策树的生长。
(2)后剪枝(postpruning):它首先构造完整的决策树,允许树过度拟合训练数据,然后对那些置信度不够的结点子树用叶子结点来代替,该叶子的类标号用该结点子树中最频繁的类标记。后剪枝的剪枝过程是删除一些子树,然后用其叶子节点代替,这个叶子节点所标识的类别通过大多数原则(majority class criterion)确定。所谓大多数原则,是指剪枝过程中, 将一些子树删除而用叶节点代替,这个叶节点所标识的类别用这棵子树中大多数训练样本所属的类别来标识,所标识的类称为majority class .相比于先剪枝,这种方法更常用,正是因为在先剪枝方法中精确地估计何时停止树增长很困难。
后剪枝的方法
1)REP方法是一种比较简单的后剪枝的方法,在该方法中,可用的数据被分成两个样例集合:一个训练集用来形成学习到的决策树,一个分离的验证集用来评估这个决策树在后续数据上的精度,确切地说是用来评估修剪这个决策树的影响。这个方法的动机是:即使学习器可能会被训练集中的随机错误和巧合规律所误导,但验证集合不大可能表现出同样的随机波动。所以验证集可以用来对过度拟合训练集中的虚假特征提供防护检验。
该剪枝方法考虑将书上的每个节点作为修剪的候选对象,决定是否修剪这个结点有如下步骤组成:
1:删除以此结点为根的子树
2:使其成为叶子结点
3:赋予该结点关联的训练数据的最常见分类
4:当修剪后的树对于验证集合的性能不会比原来的树差时,才真正删除该结点
因为训练集合的过拟合,使得验证集合数据能够对其进行修正,反复进行上面的操作,从底向上的处理结点,删除那些能够最大限度的提高验证集合的精度的结点,直到进一步修剪有害为止(有害是指修剪会减低验证集合的精度)。
REP是最简单的后剪枝方法之一,不过由于使用独立的测试集,原始决策树相比,修改后的决策树可能偏向于过度修剪。这是因为一些不会再测试集中出现的很稀少的训练集实例所对应的分枝在剪枝过如果训练集较小,通常不考虑采用REP算法。
尽管REP有这个缺点,不过REP仍然作为一种基准来评价其它剪枝算法的性能。它对于两阶段决策树学习方法的优点和缺点提供了了一个很好的学习思路。由于验证集合没有参与决策树的创建,所以用REP剪枝后的决策树对于测试样例的偏差要好很多,能够解决一定程度的过拟合问题。
2)PEP,悲观错误剪枝,悲观错误剪枝法是根据剪枝前后的错误率来判定子树的修剪。该方法引入了统计学上连续修正的概念弥补REP中的缺陷,在评价子树的训练错误公式中添加了一个常数,假定每个叶子结点都自动对实例的某个部分进行错误的分类。它不需要像REP(错误率降低修剪)样,需要用部分样本作为测试数据,而是完全使用训练数据来生成决策树,又用这些训练数据来完成剪枝。决策树生成和剪枝都使用训练集, 所以会产生错分。
把一棵子树(具有多个叶子节点)的分类用一个叶子节点来替代的话,在训练集上的误判率肯定是上升的,但是在测试数据上不一定,我们需要把子树的误判计算加上一个经验性的惩罚因子,用于估计它在测试数据上的误判率。对于一棵叶子节点,它覆盖了N个样本,其中有E个错误,那么该叶子节点的错误率为(E+0.5)/N。这个0.5就是惩罚因子,那么对于该棵子树,假设它有L个叶子节点,则该子树的误判率估计为:
剪枝后该子树内部节点变成了叶子节点,该叶子结点的误判个数J同样也需要加上一个惩罚因子,变成J+0.5。那么子树是否可以被剪枝就取决于剪枝后的错误J+0.5在
的标准误差内。对于样本的误差率e,我们可以根据经验把它估计成伯努利分布,那么可以估计出该子树的误判次数均值和标准差
使用训练数据,子树总是比替换为一个叶节点后产生的误差小,但是使用校正的误差计算方法却并非如此。剪枝的条件:当子树的误判个数大过对应叶节点的误判个数一个标准差之后,就决定剪枝:
这个条件就是剪枝的标准。当然并不一定非要大一个标准差,可以给定任意的置信区间,我们设定一定的显著性因子,就可以估算出误判次数的上下界。
决策树模型评估
自助法(bootstrap):
训练集是对于原数据集的有放回抽样,如果原始数据集N,可以证明,大小为N的自助样本大约包含原数据63.2%的记录。当N充分大的时候,1-(1-1/N)^(N) 概率逼近 1-e^(-1)=0.632。抽样 b 次,产生 b 个bootstrap样本,则,总准确率为(accs为包含所有样本计算的准确率):
准确度的区间估计:
将分类问题看做二项分布,则有:
令 X 为模型正确分类,p 为准确率,X 服从均值 Np、方差 Np(1-p)的二项分布。acc=X/N为均值 p,方差 p(1-p)/N 的二项分布。acc 的置信区间:
'''
scikit-learn中有两类决策树,它们均采用优化的CART决策树算法。
'''
from sklearn.tree import DecisionTreeRegressor
'''
回归决策树
'''
DecisionTreeRegressor(criterion="mse",
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,
presort=False)
'''
参数含义:
1.criterion:string, optional (default="mse")
它指定了切分质量的评价准则。默认为'mse'(mean squared error)。
2.splitter:string, optional (default="best")
它指定了在每个节点切分的策略。有两种切分策咯:
(1).splitter='best':表示选择最优的切分特征和切分点。
(2).splitter='random':表示随机切分。
3.max_depth:int or None, optional (default=None)
指定树的最大深度。如果为None,则表示树的深度不限,直到
每个叶子都是纯净的,即叶节点中所有样本都属于同一个类别,
或者叶子节点中包含小于min_samples_split个样本。
4.min_samples_split:int, float, optional (default=2)
整数或者浮点数,默认为2。它指定了分裂一个内部节点(非叶子节点)
需要的最小样本数。如果为浮点数(0到1之间),最少样本分割数为ceil(min_samples_split * n_samples)
5.min_samples_leaf:int, float, optional (default=1)
整数或者浮点数,默认为1。它指定了每个叶子节点包含的最少样本数。
如果为浮点数(0到1之间),每个叶子节点包含的最少样本数为ceil(min_samples_leaf * n_samples)
6.min_weight_fraction_leaf:float, optional (default=0.)
它指定了叶子节点中样本的最小权重系数。默认情况下样本有相同的权重。
7.max_feature:int, float, string or None, optional (default=None)
可以是整数,浮点数,字符串或者None。默认为None。
(1).如果是整数,则每次节点分裂只考虑max_feature个特征。
(2).如果是浮点数(0到1之间),则每次分裂节点的时候只考虑int(max_features * n_features)个特征。
(3).如果是字符串'auto',max_features=n_features。
(4).如果是字符串'sqrt',max_features=sqrt(n_features)。
(5).如果是字符串'log2',max_features=log2(n_features)。
(6).如果是None,max_feature=n_feature。
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).如果不为None,则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.presort: bool, optional (default=False)
指定是否需要提前排序数据从而加速寻找最优切分的过程。设置为True时,对于大数据集
会减慢总体的训练过程;但是对于一个小数据集或者设定了最大深度的情况下,会加速训练过程。
属性:
1.feature_importances_ : array of shape = [n_features]
特征重要性。该值越高,该特征越重要。
特征的重要性为该特征导致的评价准则的(标准化的)总减少量。它也被称为基尼的重要性
2.max_feature_:int
max_features推断值。
3.n_features_:int
执行fit的时候,特征的数量。
4.n_outputs_ : int
执行fit的时候,输出的数量。
5.tree_ : 底层的Tree对象。
Notes:
控制树大小的参数的默认值(例如``max_depth``,``min_samples_leaf``等)导致完全成长和未剪枝的树,
这些树在某些数据集上可能表现很好。为减少内存消耗,应通过设置这些参数值来控制树的复杂度和大小。
方法:
1.fit(X,y):训练模型。
2.predict(X):预测。
'''
from sklearn.tree import DecisionTreeClassifier
'''
分类决策树
'''
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时,对于大数据集
会减慢总体的训练过程;但是对于一个小数据集或者设定了最大深度的情况下,会加速训练过程。
属性:
1.classes_:array of shape = [n_classes] or a list of such arrays
类别的标签值。
2.feature_importances_ : array of shape = [n_features]
特征重要性。越高,特征越重要。
特征的重要性为该特征导致的评价准则的(标准化的)总减少量。它也被称为基尼的重要性
3.max_features_ : int
max_features的推断值。
4.n_classes_ : int or list
类别的数量
5.n_features_ : int
执行fit后,特征的数量
6.n_outputs_ : int
执行fit后,输出的数量
7.tree_ : Tree object
树对象,即底层的决策树。
方法:
1.fit(X,y):训练模型。
2.predict(X):预测
3.predict_log_poba(X):预测X为各个类别的概率对数值。
4.predict_proba(X):预测X为各个类别的概率值。
代码
import numpy as np
import pandas as pd
from sklearn.feature_extraction import DictVectorizer
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn.ensemble import RandomForestClassifier
import pandas as pd
def de():
# 获取数据
taitan = pd.read_csv("train.csv")
titan = pd.read_csv("train.csv")
# print(taitan)
# 处理数据,找出目标值和特征值
x = taitan[['Pclass', 'Age', 'Sex']]
# x = titan[['Pclass', 'Age', 'Sex']]
y = taitan['Survived']
# y = titan['Survived']
x['Age'].fillna(x['Age'].mean(), inplace=True)
# x['Age'].fillna(x['Age'].mean(), inplace=True)
# 分割数据到训练集和
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25)
# 进行特征工程
# one-hot编码
dict = DictVectorizer(sparse=False)
x_train = dict.fit_transform(x_train.to_dict(orient='records'))
print(dict.get_feature_names())
x_test = dict.transform(x_test.to_dict(orient='records'))
# print(x_train)
# 使用决策树
dec = DecisionTreeClassifier()
dec.fit(x_train, y_train)
# print('预测的准确率:',dec.score(x_test,y_test))
# 导出决策树的结构
export_graphviz(
dec,
out_file='tree.dot',
feature_names=[
'AGE',
'Pclass',
'Sex=WOMAN',
'Sex=MAN'])
# dot - Tpng tree.dot - o tree.png 当前目录下cmd 运行转化成png 格式
# 随机森林进行预测
rf = RandomForestClassifier()
# 网格搜索和交叉验证
param = {
'n_estimators': [
120, 200, 500, 800, 1200], 'max_depth': [
5, 8, 15, 25, 30]}
gc = GridSearchCV(rf, param_grid=param, cv=2)
gc.fit(x_train, y_train)
print('准确率:', gc.score(x_test, y_test))
print('查看选择的模型:', gc.best_params_)
return None
if __name__ == '__main__':
de()