集成方法:渐进梯度回归树 GBRT(迭代决策树)

集成方法:渐进梯度回归树 GBRT(迭代决策树)

集成方法:渐进梯度回归树 GBRT(迭代决策树)_数据结构与算法_皮皮 blog-CSDN 博客

另外一篇文章对于提升树和梯度提升树有更好的讨论:https://www.cnblogs.com/jiading/articles/12899688.html

单决策树 C4.5 由于功能太简单,并且非常容易出现过拟合的现象,于是引申出了许多变种决策树,就是将单决策树进行模型组合,形成多决策树,比较典型的就是迭代决策树 GBRT 和随机森林 RF。在最近几年的 paper 上,如 iccv 这种重量级会议,iccv 09 年的里面有不少文章都是与 Boosting 和随机森林相关的。模型组合 + 决策树相关算法有两种比较基本的形式:随机森林 RF 与 GBDT,其他比较新的模型组合 + 决策树算法都是来自这两种算法的延伸。首先说明一下,GBRT 这个算法有很多名字,但都是同一个算法:GBRT (Gradient BoostRegression Tree) 渐进梯度回归树,GBDT (Gradient BoostDecision Tree) 渐进梯度决策树,MART (MultipleAdditive Regression Tree) 多决策回归树,Tree Net 决策树网络。

GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结论累加起来做最终答案。它在被提出之初就和 SVM 一起被认为是泛化能力(generalization) 较强的算法。近些年更因为被用于搜索排序的机器学习模型而引起大家关注。GBRT 是回归树,不是分类树(尽管 GBDT 调整后也可用于分类但不代表 GBDT 的树是分类树)。其核心就在于,每一棵树是从之前所有树的残差中来学习的。为了防止过拟合,和 Adaboosting 一样,也加入了 boosting 这一项。

GBDT 主要由三个概念组成:Regression Decistion Tree(即 DT),Gradient Boosting(即 GB),Shrinkage (算法的一个重要演进分枝,目前大部分源码都按该版本实现)。搞定这三个概念后就能明白 GBDT 是如何工作的,要继续理解它如何用于搜索排序则需要额外理解 RankNet 概念。

Gradient Tree Boosting 或 Gradient Boosted Regression Trees(GBRT) 是一个 boosting 的泛化表示,它使用了不同的 loss 函数。GBRT 是精确、现成的过程,用于解决回归 / 分类问题。Gradient Tree Boosting 模型则用于许多不同的领域:比如:网页搜索 Ranking、ecology 等。

GBRT 优缺点

GBRT 的优点是:
天然就可处理不同类型的数据(= 各种各样的 features)
预测能力强
对空间外的异常点处理很健壮(通过健壮的 loss 函数)
GBRT 的缺点是:
扩展性不好,因为 boosting 天然就是顺序执行的,很难并行化

回归树是如何工作的?

我们以对人的性别判别 / 年龄预测为例来说明,每个 instance 都是一个我们已知性别 / 年龄的人,而 feature 则包括这个人上网的时长、上网的时段、网购所花的金额等。
分类树,我们知道 C4.5 分类树在每次分枝时,是穷举每一个 feature 的每一个阈值,找到使得按照 feature<= 阈值,和 feature> 阈值分成的两个分枝的熵最大的 feature 和阈值(熵最大的概念可理解成尽可能每个分枝的男女比例都远离 1:1),按照该标准分枝得到两个新节点,用同样方法继续分枝直到所有人都被分入性别唯一的叶子节点,或达到预设的终止条件,若最终叶子节点中的性别不唯一,则以多数人的性别作为该叶子节点的性别。
回归树总体流程类似,不过在每个节点(不一定是叶子节点)都会得一个预测值,以年龄为例,该预测值等于属于这个节点的所有人年龄的平均值 {Note: 分裂点最优值是分裂点所有 x 对应 y 值的均值 c,因内部最小平方误差最小 [统计学习方法 5.5CART 算法]}。分枝时穷举每一个 feature 的每个阈值找最好的分割点,但衡量最好的标准不再是最大熵,而是最小化均方差 -- 即(每个人的年龄 - 预测年龄)^2 的总和 / N,或者说是每个人的预测误差平方和 除以 N。这很好理解,被预测出错的人数越多,错的越离谱,均方差就越大,通过最小化均方差能够找到最靠谱的分枝依据。分枝直到每个叶子节点上人的年龄都唯一(这太难了)或者达到预设的终止条件(如叶子个数上限),若最终叶子节点上人的年龄不唯一,则以该节点上所有人的平均年龄做为该叶子节点的预测年龄。

img

[统计学习方法 5.5CART 算法]

算法原理

不是每棵树独立训练

Boosting,迭代,即通过迭代多棵树来共同决策。这怎么实现呢?难道是每棵树独立训练一遍,比如 A 这个人,第一棵树认为是 10 岁,第二棵树认为是 0 岁,第三棵树认为是 20 岁,我们就取平均值 10 岁做最终结论?-- 当然不是!且不说这是投票方法并不是 GBDT,只要训练集不变,独立训练三次的三棵树必定完全相同,这样做完全没有意义。之前说过,GBDT 是把所有树的结论累加起来做最终结论的,所以可以想到每棵树的结论并不是年龄本身,而是年龄的一个累加量。

GBDT 的核心就在于,每一棵树学的是之前所有树结论和的残差,这个残差就是一个加预测值后能得真实值的累加量。比如 A 的真实年龄是 18 岁,但第一棵树的预测年龄是 12 岁,差了 6 岁,即残差为 6 岁。那么在第二棵树里我们把 A 的年龄设为 6 岁去学习,如果第二棵树真的能把 A 分到 6 岁的叶子节点,那累加两棵树的结论就是 A 的真实年龄;如果第二棵树的结论是 5 岁,则 A 仍然存在 1 岁的残差,第三棵树里 A 的年龄就变成 1 岁,继续学。这就是 Gradient Boosting 在 GBDT 中的意义。

残差提升

**算法流程解释 1

**

img

\0. 给定一个初始值

\1. 建立 M 棵决策树(迭代 M 次){Note: 每次迭代生成一棵决策树}

\2. 对函数估计值 F(x) 进行 Logistic 变换(Note: 只是归一化而已)

\3. 对于 K 各分类进行下面的操作(其实这个 for 循环也可以理解为向量的操作,每个样本点 xi 都对应了 K 种可能的分类 yi,所以 yi,F(xi),p(xi) 都是一个 K 维向量)

\4. 求得残差减少的梯度方向

\5. 根据每个样本点 x,与其残差减少的梯度方向,得到一棵由 J 个叶子节点组成的决策树

\6. 当决策树建立完成后,通过这个公式,可以得到每个叶子节点的增益(这个增益在预测时候用的)

​ 每个增益的组成其实也是一个 K 维向量,表示如果在决策树预测的过程中,如果某个样本点掉入了这个叶子节点,则其对应的 K 个分类的值是多少。比如 GBDT 得到了三棵决策树,一个样本点在预测的时候,也会掉入 3 个叶子节点上,其增益分别为(假设为 3 分类问题):

(0.5, 0.8, 0.1), (0.2, 0.6, 0.3), (0.4, .0.3, 0.3),那么这样最终得到的分类为第二个,因为选择分类 2 的决策树是最多的。

\7. 将当前得到的决策树与之前的那些决策树合并起来,作为一个新的模型(跟 6 中的例子差不多)

算法流程解释 2

img

img

img

梯度提升

不同于前面的残差提升算法,这里使用 loss 函数的梯度近似残差(对于平方 loss 其实就是残差,一般 loss 函数就是残差的近似)。为什么要这样做呢,请看这篇文章:https://www.cnblogs.com/jiading/articles/12899791.html。

img

img

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

GBRT 示例 1(残差)

​ 年龄预测,简单起见训练集只有 4 个人,A,B,C,D,他们的年龄分别是 14,16,24,26。其中 A、B 分别是高一和高三学生;C,D 分别是应届毕业生和工作两年的员工。如果是用一棵传统的回归决策树来训练,会得到如下图 1 所示结果:

img

​ 现在我们使用 GBDT 来做这件事,由于数据太少,我们限定叶子节点做多有两个,即每棵树只有一个分枝,并且限定只学两棵树。我们会得到如下图 2 所示结果:

img

​ 在第一棵树分枝和图 1 一样,由于 A,B 年龄较为相近,C,D 年龄较为相近,他们被分为两拨,每拨用平均年龄作为预测值。此时计算残差(残差的意思就是: A 的预测值 + A 的残差 = A 的实际值),所以 A 的残差就是 16-15=1(注意,A 的预测值是指前面所有树累加的和,这里前面只有一棵树所以直接是 15,如果还有树则需要都累加起来作为 A 的预测值)。进而得到 A,B,C,D 的残差分别为 - 1,1,-1,1。然后我们拿残差替代 A,B,C,D 的原值,到第二棵树去学习,如果我们的预测值和它们的残差相等,则只需把第二棵树的结论累加到第一棵树上就能得到真实年龄了。这里的数据显然是我可以做的,第二棵树只有两个值 1 和 - 1,直接分成两个节点。此时所有人的残差都是 0,即每个人都得到了真实的预测值。换句话说,现在 A,B,C,D 的预测值都和真实年龄一致了。

A: 14 岁高一学生,购物较少,经常问学长问题;预测年龄 A = 15 – 1 = 14

B: 16 岁高三学生;购物较少,经常被学弟问问题;预测年龄 B = 15 + 1 = 16

C: 24 岁应届毕业生;购物较多,经常问师兄问题;预测年龄 C = 25 – 1 = 24

D: 26 岁工作两年员工;购物较多,经常被师弟问问题;预测年龄 D = 25 + 1 = 26

问题

1)既然图 1 和图 2 最终效果相同,为何还需要 GBDT 呢?
答案是过拟合。过拟合是指为了让训练集精度更高,学到了很多” 仅在训练集上成立的规律 “,导致换一个数据集当前规律就不适用了。其实只要允许一棵树的叶子节点足够多,训练集总是能训练到 100% 准确率的(大不了最后一个叶子上只有一个 instance)。在训练精度和实际精度(或测试精度)之间,后者才是我们想要真正得到的。
我们发现图 1 为了达到 100% 精度使用了 3 个 feature(上网时长、时段、网购金额),其中分枝 “上网时长> 1.1h” 很显然已经过拟合了,这个数据集上 A,B 也许恰好 A 每天上网 1.09h, B 上网 1.05 小时,但用上网时间是不是 > 1.1 小时来判断所有人的年龄很显然是有悖常识的;
相对来说图 2 的 boosting 虽然用了两棵树 ,但其实只用了 2 个 feature 就搞定了,后一个 feature 是问答比例,显然图 2 的依据更靠谱。(当然,这里是故意做的数据,所以才能靠谱得如此) Boosting 的最大好处在于,每一步的残差计算其实变相地增大了分错 instance 的权重,而已经分对的 instance 则都趋向于 0。这样后面的树就能越来越专注那些前面被分错的 instance。就像我们做互联网,总是先解决 60% 用户的需求凑合着,再解决 35% 用户的需求,最后才关注那 5% 人的需求,这样就能逐渐把产品做好,因为不同类型用户需求可能完全不同,需要分别独立分析。
2)Gradient 呢?不是 “G”BDT 么?
到目前为止,我们的确没有用到求导的 Gradient。在当前版本 GBDT 描述中,的确没有用到 Gradient,该版本用残差作为全局最优的绝对方向(lz 可能不知道具体步长吧?),并不需要 Gradient 求解。

那么哪里体现了 Gradient 呢?其实回到第一棵树结束时想一想,无论此时的 cost function 是什么,是均方差还是均差,只要它以误差作为衡量标准,残差向量 (-1, 1, -1, 1) 都是它的全局最优方向,这就是 Gradient。

lz 补充一句,均方差的梯度不就是残差吗,这就是梯度!(其它的 loss 函数就不一定了,但是残差向量总是全局最优的,梯度一般都是残差的近似)

3)这是 boosting?Adaboost?
这是 boosting,但不是 Adaboost。GBDT 不是 Adaboost Decistion Tree。就像提到决策树大家会想起 C4.5,提到 boost 多数人也会想到 Adaboost。Adaboost 是另一种 boost 方法,它按分类对错,分配不同的 weight,计算 cost function 时使用这些 weight,从而让 “错分的样本权重越来越大,使它们更被重视”。而这里我们没有为错分的数据人为设置weight,也没有用指数计算各个分类器之间的权重,所以不是一种adaboost算法

Bootstrap 也有类似思想,它在每一步迭代时不改变模型本身,也不计算残差,而是从 N 个 instance 训练集中按一定概率重新抽取 N 个 instance 出来(单个 instance 可以被重复 sample),对着这 N 个新的 instance 再训练一轮。由于数据集变了迭代模型训练结果也不一样,而一个 instance 被前面分错的越厉害,它的概率就被设的越高,这样就能同样达到逐步关注被分错的 instance,逐步完善的效果。

Adaboost 的方法被实践证明是一种很好的防止过拟合的方法,但至于为什么至今没从理论上被证明。GBDT 也可以在使用残差的同时引入 Bootstrap re-sampling,GBDT 多数实现版本中也增加的这个选项,但是否一定使用则有不同看法。re-sampling 一个缺点是它的随机性,即同样的数据集合训练两遍结果是不一样的,也就是模型不可稳定复现,这对评估是很大挑战,比如很难说一个模型变好是因为你选用了更好的 feature,还是由于这次 sample 的随机因素。

GBRT 示例 2(残差)

选取回归树的分界点建立回归树

img

img

使用残差继续训练新的回归树

img

img

GBRT 适用范围

​ 该版本的 GBRT 几乎可用于所有的回归问题(线性 / 非线性),相对 logistic regression 仅能用于线性回归,GBRT 的适用面非常广。亦可用于二分类问题(设定阈值,大于阈值为正例,反之为负例)。

搜索引擎排序应用 RankNet

​ 搜索排序关注各个 doc 的顺序而不是绝对值,所以需要一个新的 cost function,而 RankNet 基本就是在定义这个 cost function,它可以兼容不同的算法(GBDT、神经网络...)。
​ 实际的搜索排序使用的是 Lambda MART 算法,必须指出的是由于这里要使用排序需要的 cost function,LambdaMART 迭代用的并不是残差。Lambda 在这里充当替代残差的计算方法,它使用了一种类似 Gradient * 步长模拟残差的方法。这里的 MART 在求解方法上和之前说的残差略有不同,其区别描述见这里。
​ 搜索排序也需要训练集,但多数用人工标注实现,即对每个 (query, doc)pair 给定一个分值(如 1, 2, 3, 4),分值越高越相关,越应该排到前面。RankNet 就是基于此制定了一个学习误差衡量方法,即 cost function。RankNet 对任意两个文档 A,B,通过它们的人工标注分差,用 sigmoid 函数估计两者顺序和逆序的概率 P1。然后同理用机器学习到的分差计算概率 P2(sigmoid 的好处在于它允许机器学习得到的分值是任意实数值,只要它们的分差和标准分的分差一致,P2 就趋近于 P1)。这时利用 P1 和 P2 求的两者的交叉熵,该交叉熵就是 cost function。
​ 有了 cost function,可以求导求 Gradient,Gradient 即每个文档得分的一个下降方向组成的 N 维向量,N 为文档个数(应该说是 query-doc pair 个数)。这里仅仅是把”求残差 “的逻辑替换为” 求梯度“。每个样本通过 Shrinkage 累加都会得到一个最终得分,直接按分数从大到小排序就可以了。

[【机器学习】迭代决策树 GBRT(渐进梯度回归树)]

皮皮 blog

python sklearn 实现

分类

sklearn.ensemble.GradientBoostingClassifier(loss='deviance', learning_rate=0.1, n_estimators=100, subsample=1.0, criterion='friedman_mse', min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_depth=3, min_impurity_split=1e-07, init=None, random_state=None, max_features=None, verbose=0, max_leaf_nodes=None, warm_start=False, presort='auto')

超过 2 个分类时,需要在每次迭代时引入 n_classes 的回归树,因此,总的索引树为(n_classes * n_estimators)。对于分类数目很多的情况,强烈推荐你使用 RandomForestClassifier 来替代 GradientBoostingClassifier

回归

sklearn.ensemble.GradientBoostingRegressor(loss='ls', learning_rate=0.1, n_estimators=100, subsample=1.0, criterion='friedman_mse', min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_depth=3, min_impurity_split=1e-07, init=None, random_state=None, max_features=None, alpha=0.9, verbose=0, max_leaf_nodes=None, warm_start=False, presort='auto')

参数:

n_estimators : int (default=100) 迭代次数,也就是弱学习器的个数

The number of boosting stages to perform. Gradient boostingis fairly robust to over-fitting so a large number usuallyresults in better performance.

The plot on the left shows the train and test error at each iteration.The train error at each iteration is stored in thetrain_score_ attributeof the gradient boosting model. The test error at each iterations can be obtainedvia the staged_predict method which returns agenerator that yields the predictions at each stage. Plots like these can be usedto determine the optimal number of trees (i.e. n_estimators) by early stopping.

img

控制树的 size

回归树的基础学习器(base learners)的 size,定义了可以被 GB 模型捕获的各种交互的 level。通常,一棵树的深度为 h,可以捕获 h 阶的影响因子 (interactions)。控制各个回归树的 size 有两种方法。
1 指定 max_depth=h,那么将会长成深度为 h 的完整二元树。这样的树至多有 2^h 个叶子,以及 2^h-1 中间节点。
2 另一种方法:你可以通过指定叶子节点的数目(max_leaf_nodes)来控制树的 size。这种情况下,树将使用最优搜索 (best-first search) 的方式生成,并以最高不纯度(impurity)的方式展开。如果树的 max_leaf_nodes=k,表示具有 k-1 个分割节点,可以建模最高 (max_leaf_nodes-1) 阶的 interactions。
我们发现,max_leaf_nodes=k 与 max_depth=k-1 进行比较,训练会更快,只会增大一点点的训练误差(training error)。参数 max_leaf_nodes 对应于 gradient boosting 中的变量 J,与 R 提供的 gbm 包的参数 interaction.depth 相关,为:max_leaf_nodes == interaction.depth + 1。

数学公式 Mathematical formulation

GBRT considers additive models of the following form:

where are the basis functions which are usually called weak learners in the context of boosting. Gradient Tree Boosting uses decision trees of fixed size as weak learners. Decision trees have a number of abilities that make them valuable for boosting, namely the ability to handle data of mixed type and the ability to model complex functions.

Similar to other boosting algorithms GBRT builds the additive model in a forward stage wise fashion: 前向分步算法

At each stage the decision tree is chosen to minimize the loss function given the current model and its fit

Note: 应该是 F_{m-1}(x_i) + h(x) 吧,残差为 yi - (F_{m-1}(x_i) + h(x)) 训练下一个回归树

The initial model is problem specific, for least-squares regression one usually chooses the mean of the target values.

Note:

The initial model can also be specified via the init argument. The passed object has to implement fit and predict.

Gradient Boosting attempts to solve this minimization problem numerically via steepest descent: The steepest descent direction is the negative gradient of the loss function evaluated at the current model which can be calculated for any differentiable loss function:

Note: 这里使用的是残差的近似 -- 梯度来计算残差的。

Where the step length is chosen using line search:

The algorithms for regression and classification only differ in the concrete loss function used.

loss 函数

回归

  • 最小二乘法 Least squares(’ls’):最自然的选择,因为它的计算很简单。初始模型通过 target 的平均值来给出。
  • 最小绝对偏差 Least absolute deviation (’lad’):一个健壮的 loss 函数,用于回归。初始模型通过 target 的中值来给出。
  • Huber (‘huber’): Another robust loss function that combinesleast squares and least absolute deviation; use alpha tocontrol the sensitivity with regards to outliers (see [F2001] formore details).
  • Quantile (‘quantile’):A loss function for quantile regression.Use 0 < alpha < 1 to specify the quantile. This loss functioncan be used to create prediction intervals(see Prediction Intervals for Gradient Boosting Regression).

分类

  • Binomial deviance ('deviance'): The negative binomiallog-likelihood loss function for binary classification (providesprobability estimates). The initial model is given by thelog odds-ratio.
  • Multinomial deviance ('deviance'): The negative multinomiallog-likelihood loss function for multi-class classification withn_classes mutually exclusive classes. It providesprobability estimates. The initial model is given by theprior probability of each class. At each iteration n_classesregression trees have to be constructed which makes GBRT ratherinefficient for data sets with a large number of classes.
  • Exponential loss ('exponential'): The same loss functionas AdaBoostClassifier. Less robust to mislabeledexamples than 'deviance'; can only be used for binaryclassification.

正则化

缩减 Shrinkage

Shrinkage(缩减)的思想认为,每次走一小步逐渐逼近结果的效果,要比每次迈一大步很快逼近结果的方式更容易避免过拟合。即它不完全信任每一个棵残差树,它认为每棵树只学到了真理的一小部分,累加的时候只累加一小部分,通过多学几棵树弥补不足。用方程来看更清晰,即
没用 Shrinkage 时:(yi 表示第 i 棵树上 y 的预测值, y(1~i) 表示前 i 棵树 y 的综合预测值)
y(i+1) = 残差 (y1~yi), 其中: 残差 (y1~yi) = y 真实值 - y(1 ~ i)
y(1 ~ i) = SUM(y1, ..., yi)
Shrinkage 不改变第一个方程,只把第二个方程改为:
y(1 ~ i) = y(1 ~ i-1) + step * yi
即 Shrinkage 仍然以残差作为学习目标,但对于残差学习出来的结果,只累加一小部分(step * 残差)逐步逼近目标,step 一般都比较小,如 0.01~0.001(注意该 step 非 gradient 的 step),导致各个树的残差是渐变的而不是陡变的。直觉上这也很好理解,不像直接用残差一步修复误差,而是只修复一点点,其实就是把大步切成了很多小步。本质上,Shrinkage 为每棵树设置了一个 weight,累加时要乘以这个 weight,但和 Gradient 并没有关系。这个 weight 就是 step。就像 Adaboost 一样,Shrinkage 能减少过拟合发生也是经验证明的,目前还没有看到从理论的证明

[f2001] 提出了一种简单的正则化策略,它通过一个因子 v 将每个弱学习器的贡献进行归一化(为什么学习率 v 能将每个弱学习器的贡献进行归一化?)。

参数 v 也被称为学习率(learning rate),因为它可以对梯度下降的步长进行调整;它可以通过 learning_rate 参数进行设定。

参数 learning_rate 会强烈影响到参数 n_estimators(即弱学习器个数)。learning_rate 的值越小,就需要越多的弱学习器数来维持一个恒定的训练误差 (training error) 常量。经验上,推荐小一点的 learning_rate 会对测试误差 (test error) 更好。[HTF2009] 推荐将 learning_rate 设置为一个小的常数(e.g. learning_rate <= 0.1),并通过 early stopping 机制来选择 n_estimators。我们可以在 [R2007] 中看到更多关于 learning_rate 与 n_estimators 的关系。

子抽样 Subsampling

[F1999] 提出了随机梯度 boosting,它将 bagging(boostrap averaging)与 GradientBoost 相结合。在每次迭代时,基础分类器 (base classifer) 都在训练数据的一个子抽样集中进行训练。子抽样以放回抽样。subsample 的典型值为:0.5。

下图展示了 shrinkage 的效果,并在模型的拟合优度(Goodness of Fit)上进行子抽样(subsampling)。我们可以很清楚看到:shrinkage 的效果比 no-shrinkage 的要好。

减小 variance 策略 1:使用 shrinkage 的子抽样可以进一步提升模型准确率。而不带 shinkage 的子抽样效果差些。

img

减小 variance 策略 2:对 features 进行子抽样(类比于 RandomForestClassifier 中的随机 split)。子抽样 features 的数目可以通过 max_features 参数进行控制。注意:使用小的 max_features 值可以极大地降低运行时长。

out-of-bag 估计

随机梯度 boosting 允许计算测试偏差(test deviance)的 out-of-bag 估计,通过计算没有落在 bootstrap 样本中的其它样本的偏差改进(i.e. out-of-bag 示例)。该提升存在属性 oob_improvement_中。oob_improvement_[i] 表示在添加第 i 步到当前预测中时,OOB 样本中的 loss 的提升。OOB 估计可以被用于模型选择,例如:决定最优的迭代数。OOB 估计通常很少用,我们推荐你使用交叉验证(cross-validation),除非当 cross-validation 十分耗时的时候。

示例:[Gradient Boosting regularization; Gradient Boosting Out-of-Bag estimates; OOB Errors for Random Forests]

内省 Interpretation

单颗决策树可以通过内省进行可视化树结构。然而,GradientBoost 模型由成百的回归树组成,不能轻易地通过对各棵决策树进行内省来进行可视化。幸运的是,已经提出了许多技术来归纳和内省 GradientBoost 模型。

feature 重要程度

通常,features 对于 target 的结果预期的贡献不是均等的;在许多情况下,大多数 features 都是不相关的。当内省一个模型时,第一个问题通常是:在预测我们的 target 时,哪些 features 对结果预测来说是重要的。

单棵决策树天生就可以通过选择合适的 split 节点进行特征选择(feature selection)。该信息可以用于计算每个 feature 的重要性;基本思想是:如果一个 feature 经常用在树的 split 节点上,那么它就越重要。这个重要性的概率可以延伸到决策树家族 ensembles 方法上,通过对每棵树的 feature 求简单平均即可。

GradientBoosting 模型的重要性分值,可以通过 feature_importances_属性来访问:

>>> from sklearn.datasets import make_hastie_10_2
>>> from sklearn.ensemble import GradientBoostingClassifier

>>> X, y = make_hastie_10_2(random_state=0)
>>> clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
...     max_depth=1, random_state=0).fit(X, y)
>>> clf.feature_importances_  
array([ 0.11,  0.1 ,  0.11,  ...

示例:Gradient Boosting regression

局部依赖

局部依赖图(Partial dependence plots :PDP)展示了 target 结果与一些目标特征(target feature)之间的依赖;边缘化(marginalizing)所有其它特征(’complement’ features)。另外,我们可以内省这两者的局部依赖性。

由于人的认知的有限,目标特征的 size 必须设置的小些(通常:1 或 2),目标特征可以在最重要的特征当中进行选择。

下图展示了关于 California 居住情况的、4 个 one-way 和一个 two-way 的局部依赖图示例:

one-way 的 PDP 图告诉我们,target 结果与 target 特征之间的相互关系(e.g. 线性 / 非线性)。左上图展示了中等收入(median income)在房价中位数(median house price)上的分布;我们可以看到它们间存在线性关系。 带有两个 target 特征的 PDP,展示了和两个特征的相关关系。例如:上图最后一张小图中,两个变量的 PDP 展示了房价中位数(median house price)与房龄(house age)和平均家庭成员数(avg. occupants)间的关系。我们可以看到两个特征间的关系:对于 AveOccup>2 的,房价与房龄(HouseAge)几乎完全独立。而 AveOccup<2 的,房价则强烈依赖年齡。

partial_dependence 模块

提供了一个很方便的函数:plot_partial_dependence 来创建 one-way 以及 two-way 的局部依赖图。下例,我们展示了如何创建一个 PDP:两个 two-way 的 PDP,feature 为 0 和 1,以及一个在这两个 feature 之间的 two-way 的 PDP:

>>> from sklearn.datasets import make_hastie_10_2
>>> from sklearn.ensemble import GradientBoostingClassifier
>>> from sklearn.ensemble.partial_dependence import plot_partial_dependence

>>> X, y = make_hastie_10_2(random_state=0)
>>> clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0, max_depth=1, random_state=0).fit(X, y)
>>> features = [0, 1, (0, 1)]
>>> fig, axs = plot_partial_dependence(clf, X, features)

对于多分类的模块,我们需要设置类的 label,通过 label 参数来创建 PDP:

>>> from sklearn.datasets import load_iris
>>> iris = load_iris()
>>> mc_clf = GradientBoostingClassifier(n_estimators=10, max_depth=1).fit(iris.data, iris.target)
>>> features = [3, 2, (3, 2)]
>>> fig, axs = plot_partial_dependence(mc_clf, X, features, label=0)

如果你需要一个局部依赖函数的原始值,而非你使用 partial_dependence 函数绘制的图:

>>> from sklearn.ensemble.partial_dependence import partial_dependence

>>> pdp, axes = partial_dependence(clf, [0], X=X)
>>> pdp  
array([[ 2.46643157,  2.46643157, ...
>>> axes  
[array([-1.62497054, -1.59201391, ...

该函数需要两个参数:

  • grid: 它控制着要评估的 PDP 的 target 特征的值
  • X: 它提供了一个很方便的模式来从训练数据集上自动创建 grid。

返回值 axis:

- 如果给定了 X,那么通过这个函数返回的 axes 给出了每个 target 特征的 axis.

对于在 grid 上的 target 特征的每个值,PDP 函数需要边缘化树的不重要特征的预测。在决策树中,这个函数可以用来评估有效性,不需要训练集数据。对于每个 grid 点,会执行一棵加权树的遍历:如果一个 split 节点涉及到’target’特征,那么接下去的左、右分枝,每个分枝都会通过根据进入该分枝的训练样本的 fraction 进行加权。最终,通过访问所有叶子的平均加权得到局部依赖。对于树的 ensemble 来说,每棵树的结果都会被平均。

注意点:

  • 带有 loss=’deviance’的分类,它的 target 结果为 logit(p)
  • 初始化模型后,target 结果的预测越精确;PDP 图不会包含在 init 模型中

示例:Partial Dependence Plots

from: http://blog.csdn.net/pipisorry/article/details/60776803

ref: [Sklearn: Gradient Tree Boosting]*

[sklearn 中的 gbt(gbdt/gbrt)]*

[GBDT(MART) 迭代决策树入门教程 | 简介 ]*

[统计学习方法 8.4 提升树]

[Ensemble methods]

[Boosting Decision Tree 入门教程 http://www.schonlau.net/publication/05stata_boosting.pdf]

[LambdaMART 用于搜索排序入门教程 http://research.microsoft.com/pubs/132652/MSR-TR-2010-82.pdf]

posted @ 2020-05-16 12:03  别再闹了  阅读(1426)  评论(0)    收藏  举报