机器学习算法总结--GBDT

参考如下

  • 机器学习(四)— 从gbdt到xgboost
  • 机器学习常见算法个人总结(面试用)
  • xgboost入门与实战(原理篇)

简介

GBDT是一个基于迭代累加的决策树算法,它通过构造一组弱的学习器(树),并把多颗决策树的结果累加起来作为最终的预测输出。

算法介绍

GBDT是希望组合一组弱的学习器的线性组合,即有:

F=argminEx,y[L(y,F(x))]F(x;pm,am)=m=0Mpmh(x;am)

上述公式中 pm 表示步长,我们可以在函数空间形式上使用梯度下降法求解,首先固定 x ,然后对 F(x) 求其最优解。下面先给出框架流程:

机器学习算法总结--GBDT_第1张图片

我们需要做的是估计 gm(x) ,它是梯度方向;通过使用决策树实现来逼近 gm(x) ,使得两者之间的距离尽可能的近,而距离的衡量方式有多种,包括均方误差和LogLoss误差。下面给出使用LogLoss损失函数的具体推导:

L(y,F)=log(1+exp(2yF))y[1,1]

Step1 首先求解初始值 F0 ,令其偏导为0。(实现时是第1棵树需要拟合的残差):

机器学习算法总结--GBDT_第2张图片

Step 2 估计 gm(x) ,并用决策树对其进行拟合。 gm(x) 是梯度,实现时是第 m 棵树需要拟合的残差:

机器学习算法总结--GBDT_第3张图片

Step 3 使用牛顿法求解下降方向步长。 rjm 是拟合的步长,实现时是每棵树的预测值。(通常实现中这一步是被省略的,改为使用Shrinkage的策略通过参数设置步长,避免过拟合。

机器学习算法总结--GBDT_第4张图片

Step 4 预测时只需要把每棵树的预测值乘以缩放因子然后相加即可得到最终的预测值:

p=predict(0)+m=1Mshrinkagepredict(dm)

若需要预测值输出区间在 [0,1] ,可作如下转换:
probability=11+e2predict

GBDT中的树是回归树,不是分类树。

RF与GBDT对比

(1)RF中树的棵树是并行生成的;GBDT中树是顺序生成的;两者中过多的树都会过拟合,但是GBDT更容易过拟合

(2)RF中每棵树分裂的特征比较随机;GBDT中前面的树优先分裂对大部分样本区分的特征,后面的树分裂对小部分样本区分特征;

(3)RF中主要参数是树的棵数;GBDT中主要参数是树的深度,一般为1

Shrinkage

Shrinkage认为,每次走一小步逐步逼近的结果要比每次迈一大步逼近结果更加容易避免过拟合。

y(1i)=y(1i1)+stepyi

优缺点

优点

  1. 精度高
  2. 能处理非线性数据
  3. 能处理多特征类型
  4. 适合低维稠密数据
  5. 模型可解释性好
  6. 不需要做特征的归一化,可以自动选择特征
  7. 能适应多种损失函数,包括均方误差和LogLoss

缺点

  1. boosting是个串行的过程,所以并行麻烦,需要考虑上下树之间的联系
  2. 计算复杂度大
  3. 不使用高维稀疏特征

调参

  1. 树的个数 100~10000
  2. 叶子的深度 3~8
  3. 学习速率 0.01~1
  4. 叶子上最大节点树 20
  5. 训练采样比例 0.5~1
  6. 训练特征采样比例 (n)

xgboost

xgboost是boosting Tree的一个很牛的实现,它在最近Kaggle比赛中大放异彩。它 有以下几个优良的特性:

  1. 显示的把树模型复杂度作为正则项加到优化目标中。
  2. 公式推导中用到了二阶导数,用了二阶泰勒展开。
  3. 实现了分裂点寻找近似算法。
  4. 利用了特征的稀疏性。
  5. 数据事先排序并且以block形式存储,有利于并行计算。
  6. 基于分布式通信框架rabit,可以运行在MPI和yarn上。(最新已经不基于rabit了)
  7. 实现做了面向体系结构的优化,针对cache和内存做了性能优化。

在项目实测中使用发现,Xgboost的训练速度要远远快于传统的GBDT实现,10倍量级。

特点

这部分内容参考了知乎上的一个问答—机器学习算法中GBDT和XGBOOST的区别有哪些?,答主是wepon大神

1.传统GBDT以CART作为基分类器,xgboost还支持线性分类器,这个时候xgboost相当于带L1和L2正则化项的逻辑斯蒂回归(分类问题)或者线性回归(回归问题)。 —可以通过booster [default=gbtree]设置参数:gbtree: tree-based models/gblinear: linear models

2.传统GBDT在优化时只用到一阶导数信息,xgboost则对代价函数进行了二阶泰勒展开,同时用到了一阶和二阶导数。顺便提一下,xgboost工具支持自定义代价函数,只要函数可一阶和二阶求导。 —对损失函数做了改进(泰勒展开,一阶信息g和二阶信息h)

3.xgboost在代价函数里加入了正则项,用于控制模型的复杂度。正则项里包含了树的叶子节点个数、每个叶子节点上输出的score的L2模的平方和。从Bias-variance tradeoff角度来讲,正则项降低了模型variance,使学习出来的模型更加简单,防止过拟合,这也是xgboost优于传统GBDT的一个特性
—正则化包括了两个部分,都是为了防止过拟合,剪枝是都有的,叶子结点输出L2平滑是新增的。

4.shrinkage and column subsampling —还是为了防止过拟合

(1)shrinkage缩减类似于学习速率,在每一步tree boosting之后增加了一个参数n(权重),通过这种方式来减小每棵树的影响力,给后面的树提供空间去优化模型。

(2)column subsampling列(特征)抽样,说是从随机森林那边学习来的,防止过拟合的效果比传统的行抽样还好(行抽样功能也有),并且有利于后面提到的并行化处理算法。

5.split finding algorithms(划分点查找算法):
(1)exact greedy algorithm—贪心算法获取最优切分点
(2)approximate algorithm— 近似算法,提出了候选分割点概念,先通过直方图算法获得候选分割点的分布情况,然后根据候选分割点将连续的特征信息映射到不同的buckets中,并统计汇总信息。
(3)Weighted Quantile Sketch—分布式加权直方图算法
这里的算法(2)、(3)是为了解决数据无法一次载入内存或者在分布式情况下算法(1)效率低的问题,以下引用的还是wepon大神的总结:

可并行的近似直方图算法。树节点在进行分裂时,我们需要计算每个特征的每个分割点对应的增益,即用贪心法枚举所有可能的分割点。当数据无法一次载入内存或者在分布式情况下,贪心算法效率就会变得很低,所以xgboost还提出了一种可并行的近似直方图算法,用于高效地生成候选的分割点。

6.对缺失值的处理。对于特征的值有缺失的样本,xgboost可以自动学习出它的分裂方向。 —稀疏感知算法

7.Built-in Cross-Validation(内置交叉验证)

XGBoost allows user to run a cross-validation at each iteration of the boosting process and thus it is easy to get the exact optimum number of boosting iterations in a single run.
This is unlike GBM where we have to run a grid-search and only a limited values can be tested.

8.continue on Existing Model(接着已有模型学习)

User can start training an XGBoost model from its last iteration of previous run. This can be of significant advantage in certain specific applications.
GBM implementation of sklearn also has this feature so they are even on this point.

9.High Flexibility(高灵活性)

**XGBoost allow users to define custom optimization objectives and evaluation criteria.
This adds a whole new dimension to the model and there is no limit to what we can do.**

10.并行化处理 —系统设计模块,块结构设计等

xgboost工具支持并行。boosting不是一种串行的结构吗?怎么并行的?注意xgboost的并行不是tree粒度的并行,xgboost也是一次迭代完才能进行下一次迭代的(第t次迭代的代价函数里包含了前面t-1次迭代的预测值)。xgboost的并行是在特征粒度上的。我们知道,决策树的学习最耗时的一个步骤就是对特征的值进行排序(因为要确定最佳分割点),xgboost在训练之前,预先对数据进行了排序,然后保存为block结构,后面的迭代中重复地使用这个结构,大大减小计算量。这个block结构也使得并行成为了可能,在进行节点的分裂时,需要计算每个特征的增益,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行。

此外xgboost还设计了高速缓存压缩感知算法,这是系统设计模块的效率提升。
当梯度统计不适合于处理器高速缓存和高速缓存丢失时,会大大减慢切分点查找算法的速度。
(1)针对 exact greedy algorithm采用缓存感知预取算法
(2)针对 approximate algorithms选择合适的块大小

代码使用

下面给出简单使用xgboost这个框架的例子。

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.01, random_state=1729)
print(X_train.shape, X_test.shape)

#模型参数设置
xlf = xgb.XGBRegressor(max_depth=10, 
                        learning_rate=0.1, 
                        n_estimators=10, 
                        silent=True, 
                        objective='reg:linear', 
                        nthread=-1, 
                        gamma=0,
                        min_child_weight=1, 
                        max_delta_step=0, 
                        subsample=0.85, 
                        colsample_bytree=0.7, 
                        colsample_bylevel=1, 
                        reg_alpha=0, 
                        reg_lambda=1, 
                        scale_pos_weight=1, 
                        seed=1440, 
                        missing=None)

xlf.fit(X_train, y_train, eval_metric='rmse', verbose = True, eval_set = [(X_test, y_test)],early_stopping_rounds=100)

# 计算 auc 分数、预测
preds = xlf.predict(X_test)

一个运用到实际例子的代码,来自xgboost入门与实战(实战调参篇)

import numpy as np
import pandas as pd
import xgboost as xgb
from sklearn.cross_validation import train_test_split

#from xgboost.sklearn import XGBClassifier
#from sklearn import cross_validation, metrics   #Additional scklearn functions
#from sklearn.grid_search import GridSearchCV   #Perforing grid search
#
#import matplotlib.pylab as plt
#from matplotlib.pylab import rcParams

#记录程序运行时间
import time 
start_time = time.time()

#读入数据
train = pd.read_csv("Digit_Recognizer/train.csv")
tests = pd.read_csv("Digit_Recognizer/test.csv") 

params={
'booster':'gbtree',
'objective': 'multi:softmax', #多分类的问题
'num_class':10, # 类别数,与 multisoftmax 并用
'gamma':0.1,  # 用于控制是否后剪枝的参数,越大越保守,一般0.1、0.2这样子。
'max_depth':12, # 构建树的深度,越大越容易过拟合
'lambda':2,  # 控制模型复杂度的权重值的L2正则化项参数,参数越大,模型越不容易过拟合。
'subsample':0.7, # 随机采样训练样本
'colsample_bytree':0.7, # 生成树时进行的列采样
'min_child_weight':3, 
# 这个参数默认是 1,是每个叶子里面 h 的和至少是多少,对正负样本不均衡时的 0-1 分类而言
#,假设 h 在 0.01 附近,min_child_weight 为 1 意味着叶子节点中最少需要包含 100 个样本。
#这个参数非常影响结果,控制叶子节点中二阶导的和的最小值,该参数值越小,越容易 overfitting。 
'silent':0 ,#设置成1则没有运行信息输出,最好是设置为0.
'eta': 0.007, # 如同学习率
'seed':1000,
'nthread':7,# cpu 线程数
#'eval_metric': 'auc'
}

plst = list(params.items())
num_rounds = 5000 # 迭代次数

train_xy,val = train_test_split(train, test_size = 0.3,random_state=1)
#random_state is of big influence for val-auc
y = train_xy[:, 0]
X = train_xy[:, 1:]
val_y = val[:, 0]
val_X = val[:, 1:]

xgb_val = xgb.DMatrix(val_X,label=val_y)
xgb_train = xgb.DMatrix(X, label=y)
xgb_test = xgb.DMatrix(tests)


watchlist = [(xgb_train, 'train'),(xgb_val, 'val')]

# training model 
# early_stopping_rounds 当设置的迭代次数较大时,early_stopping_rounds 可在一定的迭代次数内准确率没有提升就停止训练
model = xgb.train(plst, xgb_train, num_rounds, watchlist,early_stopping_rounds=100)

model.save_model('./model/xgb.model') # 用于存储训练出的模型
print "best best_ntree_limit",model.best_ntree_limit 

print "跑到这里了model.predict"
preds = model.predict(xgb_test,ntree_limit=model.best_ntree_limit)

np.savetxt('xgb_submission.csv',np.c_[range(1,len(tests)+1),preds],delimiter=',',header='ImageId,Label',comments='',fmt='%d')

#输出运行时长
cost_time = time.time()-start_time
print "xgboost success!",'\n',"cost time:",cost_time,"(s)"

所使用的数据集是Kaggle上的Classify handwritten digits using the famous MNIST data–手写数字识别数据集,即Mnist数据集。

你可能感兴趣的:(机器学习,算法)