参考资料:信息论基础、机器学习信息论基础、决策树、回归树的原理、如何防止过拟合问题、sklearn参数
Table of Contents
1. 信息论基础
科学真理最重要的是两点,一是能量,二是信息。一是通过爱因斯坦的 ,物质和能量其实是一回事,另外如何描写和衡量信息则是更重要的,爱因斯坦本人曾经说过随着时间的改变质量方程可能会错,而这个方程不会。
信息论是应用数学的一个分支,主要研究的是对一个信号能够提供信息的多少进行量化,最初用于研究在一个含有噪声的信道上用离散的字母表来发送消息,指导最优的通信编码等。
1.1 熵
原本物理学中的定义,后来香农将其引申到啦信息论领域,用来表示信息量的大小。信息量大(分类越不“纯净”),对应的熵值就越大,反之亦然。
信息熵的计算公式如下:
1.2 联合熵
一维随机变量分布推广到多维随机变量分布。
1.3 条件熵
表示在已知随机变量 X 的条件下随机变量 Y 的不确定性。
条件熵定义为 X 给定条件下 Y 的条件概率分布的熵对 X 的数学期望。
1.4 信息增益
以某特征划分数据集前后的熵的差值。即待分类集合的熵和选定某个特征的条件熵之差。
1.5 基尼不纯度
即基尼指数
2.决策树的不同分类算法的原理及应用场景
决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。在机器学习中,决策树是一个预测模型,他代表的是对象属性与对象值之间的一种映射关系。Entropy = 系统的凌乱程度,使用算法ID3, C4.5和C5.0生成树算法使用熵。这一度量是基于信息学理论中熵的概念。
决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一种类别。
分类树(决策树)是一种十分常用的分类方法。他是一种监管学习,所谓监管学习就是给定一堆样本,每个样本都有一组属性和一个类别,这些类别是事先确定的,那么通过学习得到一个分类器,这个分类器能够对新出现的对象给出正确的分类。这样的机器学习就被称之为监督学习。
算法原理:
- 每次依据不同的特征信息对数据集进行划分,划分的最终结果是一棵树。
- 该树的每个子树存放一个划分集,而每个叶节点则表示最终分类结果,这样一棵树被称为决策树。
- 决策树建好之后,带着目标对象按照一定规则遍历这个决策树就能得到最终的分类结果。
该算法可以分为两大部分:
1. 构建决策树部分
2. 使用s决策树分类部分
其中,第一部分是重点难点。
2.1 ID3算法
算法流程
从上面的算法过程我们可以看出,其本质就是在不停地选择当前未被选中的特征中,最为重要的特征作为划分样本空间的依据,当信息增益达不到阈值或没有可用的样本了,决策树的递归过程也就结束了。
2.2 C4.5
ID3算法有两个明显的缺点:
1)使用信息增益进行特征选择,但信息增益是一个绝对的概念,与训练集本身的离散程度有很大的关系,当训练集本身离散程度很高时,其可改进的空间更大,能够获得的信息增益更大,反之更小,这会导致很难在开始训练前就确定一个较为合理的阈值ϵ 。
2)需要一直进行到没有特征可选为止,特征很多时树深度可能很深,无关紧要的特征也会被精确分析,从而导致过拟合。
因此,C4.5算法做出了两个改进。
- 使用信息增益比
使用信息增益比进行特征选择,其公式为:
通过这样的归一化之后,我们能够校正scale上的偏差,方便选择一个较为稳定的阈值,不需要受到数据集本身的影响
- 剪枝
既然知道了过拟合产生的原因是为了精确拟合训练集而形成了过于复杂的模型,那么剪枝就是要控制模型的复杂度,通过以下正则化的损失函数公式来实现:
2.3 CART分类树
不同于前两种算法预测结果为分类结果,CART的预测结果为概率值。并且改进了前两种算法中的一个缺点:使用信息增益或信息增益比时,可选值多的特征往往有更高的信息增益,这个可以自己做一下实验。所以在CART树中,不再采用信息增益或信息增益比,而是在做回归时采用平方误差最小化准则,在做分类时采用基尼指数最小化准则。
1)对于训练集D中的每个特征A,遍历特征每个可能的取值a,根据特征是否满足A=a 将样本分为D1 D 2 两个区间,通过以下公式计算基尼指数:
基尼指数基本公式:
选择基尼指数最小的特征A及切分点a,根据它们将样本分为两个区间,分别放入两个子节点中,递归调用这个过程直到叶子节点中样本个数少于阈值或基尼指数小于阈值。
3. 回归树原理
3.1 最简单的模型
如果预测某个连续变量的大小,最简单的模型之一就是用平均值。比如同事的平均年龄是 28 岁,那么新来了一批同事,在不知道这些同事的任何信息的情况下,直觉上用平均值 28 来预测是比较准确的,至少比 0 岁或者 100 岁要靠谱一些。我们不妨证明一下我们的直觉:
3.2 难度加深
仍然是预测同事年龄,这次我们预先知道了同事的职级,假设职级的范围是整数1-10,如何能让这个信息帮助我们更加准确的预测年龄呢?
一个思路是根据职级把同事分为两组,这两组分别应用我们之前提到的“平均值”模型。比如职级小于 5 的同事分到A组,大于或等于5的分到 B 组,A 组的平均年龄是 25 岁,B 组的平均年龄是 35 岁。如果新来了一个同事,职级是 3,应该被分到 A 组,我们就预测他的年龄是 25 岁。
3.3 最佳分割点
还有一个问题待解决,如何取一个最佳的分割点对不同职级的同事进行分组呢?
我们尝试所有 m 个可能的分割点 P_i,沿用之前的损失函数,对 A、B 两组分别计算 Loss 并相加得到 L_i。最小的 L_i 所对应的 P_i 就是我们要找的“最佳分割点”。
3.4 运用多个变量
再复杂一些,如果我们不仅仅知道了同事的职级,还知道了同事的工资(貌似不科学),该如何预测同事的年龄呢?
我们可以分别根据职级、工资计算出职级和工资的最佳分割点P_1, P_2,对应的Loss L_1, L_2。然后比较L_1和L2,取较小者。假设L_1 < L_2,那么按照P_1把不同职级的同事分为A、B两组。在A、B组内分别计算工资所对应的分割点,再分为C、D两组。这样我们就得到了AC, AD, BC, BD四组同事以及对应的平均年龄用于预测。
3.5 结论
如何实现这种1 to 2, 2 to 4, 4 to 8的算法呢?
二叉树,这种树被称为回归树,顾名思义利用树形结构求解回归问题。
4. 决策树防止过拟合手段
4.1 产生过度拟合数据问题的原因
原因1:样本问题
(1)样本里的噪音数据干扰过大,大到模型过分记住了噪音特征,反而忽略了真实的输入输出间的关系;(什么是噪音数据?)
(2)样本抽取错误,包括(但不限于)样本数量太少,抽样方法错误,抽样时没有足够正确考虑业务场景或业务特点,等等导致抽出的样本数据不能有效足够代表业务逻辑或业务场景;
(3)建模时使用了样本中太多无关的输入变量。
原因2:构建决策树的方法问题
在决策树模型搭建中,我们使用的算法对于决策树的生长没有合理的限制和修剪的话,决策树的自由生长有可能每片叶子里只包含单纯的事件数据或非事件数据,可以想象,这种决策树当然可以完美匹配(拟合)训练数据,但是一旦应用到新的业务真实数据时,效果是一塌糊涂。
上面的原因都是现象,但是其本质只有一个,那就是“业务逻辑理解错误造成的”,无论是抽样,还是噪音,还是决策树等等,如果我们对于业务背景和业务知识非常了解,非常透彻的话,一定是可以避免绝大多数过拟合现象产生的。因为在模型从确定需求,到思路讨论,到搭建,到业务应用验证,各个环节都是可以用业务敏感来防止过拟合于未然的。
4.2 解决方案
针对原因1的解决方法:
合理、有效地抽样,用相对能够反映业务逻辑的训练集去产生决策树;
针对原因2的解决方法(主要):
剪枝:提前停止树的增长或者对已经生成的树按照一定的规则进行后剪枝。
剪枝的方法
剪枝是一个简化过拟合决策树的过程。有两种常用的剪枝方法:
(1)先剪枝(prepruning):通过提前停止树的构建而对树“剪枝”,一旦停止,节点就成为树叶。该树叶可以持有子集元组中最频繁的类;
先剪枝的方法
有多种不同的方式可以让决策树停止生长,下面介绍几种停止决策树生长的方法:
限制决策树的高度和叶子结点处样本的数目
1.定义一个高度,当决策树达到该高度时就可以停止决策树的生长,这是一种最为简单的方法;
2.达到某个结点的实例具有相同的特征向量,即使这些实例不属于同一类,也可以停止决策树的生长。这种方法对于处理数据中的数据冲突问题非常有效;
3.定义一个阈值,当达到某个结点的实例个数小于该阈值时就可以停止决策树的生长;
4.定义一个阈值,通过计算每次扩张对系统性能的增益,并比较增益值与该阈值的大小来决定是否停止决策树的生长。
(2)后剪枝(postpruning):它首先构造完整的决策树,允许树过度拟合训练数据,然后对那些置信度不够的结点子树用叶子结点来代替,该叶子的类标号用该结点子树中最频繁的类标记。后剪枝的剪枝过程是删除一些子树,然后用其叶子节点代替,这个叶子节点所标识的类别通过大多数原则(majority class criterion)确定。所谓大多数原则,是指剪枝过程中, 将一些子树删除而用叶节点代替,这个叶节点所标识的类别用这棵子树中大多数训练样本所属的类别来标识,所标识的类称为majority class .相比于先剪枝,这种方法更常用,正是因为在先剪枝方法中精确地估计何时停止树增长很困难。
5. 模型评估
常用的评估分类器性能的方法:
1、保持方法
在保持(Holdout)方法中,将被标记的原始数据划分成两个不想交的集合,分别称为训练集合检验集。在训练数据集上归纳分类模型,在检验集上评估模型的性能。训练集和检验集的划分比例通常根据分析家的判断(例如,50-50,或者2/3作为训练集、1/3作为检验集)。分类器的准确率根据模型在检验集上的准确率估计。
2、随机二次抽样
可以多次重复保持方法来改进对分类器性能的估计,这种方法称作随机二次抽样(random subsampling)。设是第i次迭代的模型准确率,总准确率是
。随机二次抽样也会遇到一些与保持方法同样的问题,因为在训练阶段也没有利用尽可能多的数据。并且,由于它没有控制每个记录用于训练和检验的次数,因此,有些用于训练的记录使用的频率可能比其他记录高很多。
3、交叉验证
替代随机二次抽样的一种方法是交叉验证(cross-validation)。在该方法中,每个记录用于训练的次数相同,并且恰好检验一次。为了解释该方法,假设把数据分为相同大小的两个子集,首先,我们选择一个子集作训练集,而另一个作检验集,然后交换两个集合的角色,原先作训练集的现在做检验集,反之亦然,这种方法叫做二折交叉验证。总误差通过对两次运行的误差求和得到。在这个例子中,每个样本各作一次训练样本和检验样本。k折交叉验证是对该方法的推广,把数据分为大小相同的k份,在每次运行,选择其中一份作检验集,而其余的全作为训练集,该过程重复k次,使得每份数据都用于检验恰好一次。同样,总误差是所有k次运行的误差之和。
4、自助法
以上方法都是假定训练记录采用不放回抽样,因此,训练集合检验集都不包含重复记录。在自助(bootstrap)方法中,训练记录采用有放回抽样,即已经选作训练的记录将放回原来的记录集中,使得它等机率地被重新抽取。如果原始数据有N个记录,可以证明,平均来说,大小为N的自助样本大约包含原始数据中63.2%的记录。这是因为一个记录被自助抽样抽取的概率是,当N充分大时,该概率逐渐逼近
。没有抽中的记录就成为检验集的一部分,将训练集建立的模型应用到检验集上,得到自助样本准确率的一个估计εiεi。抽样过程重复b次,产生b个自助样本。
按照如何计算分类器的总准确率,有几种不同的自助抽样法。常用的方法之一是.632自助(.632 bootstrap),它通过组合每个自助样本的准确率()和由包含所有标记样本的训练集计算的准确率(
)计算总准确率(
):
6. sklearn参数详解,Python绘制决策树
官方回归树的example代码如下
print(__doc__)
# Import the necessary modules and libraries
import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
# Create a random dataset
rng = np.random.RandomState(1)
X = np.sort(5 * rng.rand(80, 1), axis=0)
y = np.sin(X).ravel()
y[::5] += 3 * (0.5 - rng.rand(16))
# Fit regression model
regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_1.fit(X, y)
regr_2.fit(X, y)
# Predict
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)
# Plot the results
plt.figure()
plt.scatter(X, y, s=20, edgecolor="black",
c="darkorange", label="data")
plt.plot(X_test, y_1, color="cornflowerblue",
label="max_depth=2", linewidth=2)
plt.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2)
plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
plt.legend()
plt.show()
结果如图,max_depth = 2时拟合的没有max_depth = 5好
用以下代码就可以可视化决策树了
from IPython.display import Image
from sklearn import tree
import pydotplus
#regr_1 和regr_2
dot_data = tree.export_graphviz(regr_1, out_file=None, #regr_1 是对应分类器
feature_names=['x'], #对应特征的名字
class_names=['y'], #对应类别的名字
filled=True, rounded=True,
special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_png('example.png') #保存图像
Image(graph.create_png())
max_depth=2
max_depth=5