长文详解自然语言处理算法xgboost和python实战

|小修很早就想总结一下xgboost的内容,但是每次看到一大堆公式就头大,而且网上很多资料很多都不全,下文第一部分是根据xgboost的官方中文文档编写的。纯粹是总结学习,如有侵权还请告知。

xgboost是大规模并行boosted tree的工具,它是目前最快最好的开源boosted tree工具包,比常见的工具包快10倍以上。在数据科学方面,有大量的kaggle选手选用它进行数据挖掘比赛,它也是大家常用的一种处理自然语言的算法,在有些情况下,xgboost甚至能够比神经网络的结果要好(小修之前测试过各种模型对一特定文本语言分类的性能)。在工业界规模方面,xgboost的分布式版本有广泛的可移植性,支持很多平台运行,并且保留了单机并行版本的各种优化,使得它可以很好地解决于工业界规模的问题。

1

Boosted Trees 介绍

XGBoost是“Extreme Gradient Boosting”的缩写,这里使用监督学习的元素以独立和有原则的方式解释boosted trees (增强树)。

监督学习的要素

这里先从XGBoost用于监督学习问题开始, 假设训练数据xi,目标变量为yi。这里先回顾一下监督学习的重要组成部分。

模型和参数

监督学习中的模型通常是指给定输入xi如何去预测输出yi的数学结构,例如一个常见的模型是线性回归,其中的预测是由yi= sum(wjxij)的方式给出,这是加权输入特征的线性组合叠加的方式。其实这里的预测y可以有不同的解释,取决于做的任务。线性回归中,系数w为该模型的参数,一般是需要从数据中学习的未确定的部分。

目标函数:训练损失+正则

基于对yi的不同理解,我们可以得到不同的问题,比如回归,分类,排序等,我们需要找到一种方法来找到训练数据的最佳参数,为了做到这一点,需要定义个目标函数,以给定一组数据来衡量模型的性能。对于目标函数,一般包含训练损失函数以及正则化项,。一般目标函数如下式所示:

其中L是训练损失函数,后面一项为正则化项,目标函数和各项都是参数的函数,训练损失衡量的是数据对训练数据的预测性,比如常用的训练损失函数就是预测结果和目标结果的均方误差,另一个常用的损失函数是logistic回归的损失函数:

正则化项是使用者通常忘记添加的部分,正则化项控制模型的复杂度,有助于避免过拟合,比如下面一图对于在不同的损失函数和正则化项下,对数据点的拟合结果。

对于线性模型常见的正则化有L2正则和L1正则,这样的目标函数的设计来自于统计学习中的一个重要概念,就是偏差-方差的权衡(bias-variance tradeoff),其中偏差可以理解为假设我们有无限多数据的时候,可以训练出最好的模型所拿到的误差,而方差是因为只有有限数据的随机性带来的误差,目标中的误差函数是为了让模型尽可能去拟合训练数据,这样可以得到一个比较小偏差的模型,而正则化项则鼓励更加简单的模型,因为模型简单之后,有限数据拟合出来的结果随机性比较小,不易过拟合,使得最后模型的预测更加稳定。

Tree ensembles (树集成)

上文介绍的都是监督学习的基本内容,下面来介绍关于xgboost的模型部分:树集成。树集成模型是一组classification and regression trees (CART)(分类回归树)。下面是一个简单的例子,它可以分类是否有人喜欢电脑。

把一个家庭的成员分成不同的叶子,并把他们分配到相应的叶子节点上,CART与决策树有些不同,就是叶子包含决策值,在CART中,每个叶子都有一个真实的分数,这样就超越了简单的分类。通常情况下,单颗树由于过于简单而不够强大到可以支持在实践中使用,实际使用的是所谓的树集成模型,它将多棵树的预测加到一起。

上图示两个树集成的例子,将每棵树的预测分数加起来得到最终的分数,如果你看一下这个例子,一个重要的事实就是两棵树互相补充,在数学上表示,可以表示为下式所描述的模型:

其中K是树的数量,f是函数空间F的函数,F是所有可能的CARTs的集合,所以我们的优化目标可以写成下式所示:

这里需要点出的是随机森林(random forests)的模型就是树集成,所以随机森林和增强树(boosted trees)在模型没有什么不同。不同之处只是在于我们如何训练它们,这意味着如果写一个树集成的预测服务,你只需要编写它们中的一个,它们应该直接为随机森林和增强树工作,这也是监督学习基石元素的一个例子。

Tree Boosting

在介绍完模型之后,这里介绍如何去训练学习树,按照一般监督学习模型的处理思路,需要定义一个合理的目标函数,然后尝试去优化这一目标函数。

这里假设有如下所示的目标函数,当然它是需要饱含训练损失和正则化的:

另外还有一个问题,为了每一步选择一个好的树,就需要添加一个优化目标的方法:

如果使用均方误差作为损失函数,它将是下面的形式:

均方误差的形式比较友好,具有一阶项(通常称为残差)和二次项,对于其他形式的损失,获得这么好的形式并不是那么容易,所以在一般情况下,我们把损失函数的泰勒展开到二阶

其中gi和hi的定义为:

我们删除了所有的常量之后,t步骤中的具体目标就变成了:

这成为了新树的优化目标,这个定义的一个重要优点是它只依赖于gi和hi,这就是xgboost如何支持自定义损失函数,我们可以使用完全相同的i和hi作为输入的求解器来对每个损失函数进行优化,包括逻辑回归(logistic regression),权重逻辑回归(weight logistic regression)。

模型复杂度

我们已经介绍了训练步骤,但是我们还需要定义树的复杂度,这里首先改进一棵树的定义f(x) 如下:

这里w是树叶上的分数向量,q是将每个数据点分配给叶子的函数,T是树叶的数量,在XGBoost中,我们将复杂度定义为:

当然有不止一种方法来定义复杂度,但是这个具体的方法在实践中运行良好,正则化是大多树的包容易忽略的一部分,这是因为传统的树学习算法的只强调提高不纯性(impurity),而复杂度控制则是启发式的。

The structure score (结构分数)

这是derivation的神奇部分,在对树模型进行重新格式化之后,我们可以用第t棵树来编写目标值:

其中Ii= 是分配给第j个叶子的数据点的索引集合,需要注意的是,在第二行中,我们改变了总和的索引,因为同一叶子上的所有数据点都得到了相同的分数,我们可以通过定义Gj和Hj来近一步压缩表达式:

在这个等式中wj是相互独立的,形式Gjwj+1/2(Hj + lamda)wj*wj是二次的,对于给定的结构q(x)的最好的wj,我们可以得到最好的客观规约:

最后一个方程度量一个结构q(x)到底有多好

这一切看起来有些复杂,可以看一下上面的图片,看看分数是如何计算的,基本上,对于一个给定的树结构,我们把统计gi和hi推到它们所属的叶子上,统计数据加和到一起,然后使用公式计算树是多好,除了考虑到模型的复杂度,这个分数就像决策树中的杂质测量一样(例如:熵和Gini系数)。

学习树结构

既然有来一个方法来衡量一棵树有多好,理想情况下我们会列举所有可能的树并挑选出最好的树,在实践中,这种方法是比较棘手的,所以我们会尽量一次优化树的一个层次,具体来说,我们试图将一片叶子分成两片,并得到分数(这里使用Gini系数):

这个公式可以分解为1)新左叶上的得分,2)新右叶上得分,3)原始叶子上的得分,4)附加叶子上的正则化,我们可以在这里看到一个重要的事实:如果增益小于gamma,我们最好不要添加那个分支,这正是基于树模型的剪枝技术。对于真实有价值的数据,通常需要寻找一个最佳的分割,为了有效地做到这一点,我们把所有的实例按照排序顺序排列,如下图所示:

从左到右的扫描就足以计算所有可能的拆分解决方案的结构得分,我们可以有效找到最佳的拆分。

2

xgboost的安装

1.xgboost的安装有一些依赖包,所以在安装xgboost之前需要安装这些依赖包,为了方便安装,这里推荐直接安装anaconda,这里面集成了绝大多数的第三方库.

2.xgboost可以在官网上下载,下载下来

3: 这里以liunix系统安装过程为例子介绍安装过程:

首先需要检查linux系统是不是安装了gcc-c++,检查命令为:

rpm -qa grep gcc

如果发现没有安装可以使用如下命令安装:

yum install gcc-c++

确认gcc-c++已经安装之后,可以开始编译和安装工作了,然后进入到下载的xgboost的文件夹中使用下面的命令进行:

make

cd python-package

python setup.py install --user

最后验证,在终端中输入python,进入python编译器,输入import xgboost,如果没有报错,则按装成功。

3

python实践xgboost:对文本进行分类

这里我只给出xgboost_model的核心代码,如下所示,至于xgboost_model的参数可以根据之前小修介绍的jieba分词和Tfidf获取每条文本去获取训练文本和测试文本的weight:

在头文件中需要包含: import xgboost as xgb.

这里介绍xgboost中的一些参数,当然一些参数可以对照第一部分的内容进行理解:

xgboost所有的参数可以分为三类: 1. 通用参数:宏观函数控制,2. Booster参数: 控制每一步的booster, 3. 学习目标参数:控制训练目的的表现。

1: 通用参数:

booster [默认是gbtree]:gbtree基于树的模型,gbliner为基于线性模型

silent[默认为0]:值为1时,静默模式开启,不会输出任何信息

nthread[默认值为最大可能的线程数]:这个参数用来进行多线程控制,应当输入系统的核数,

2: booster参数

这里只介绍tree booster的,因为它的表现远胜于linear booster,所以linear booster一般很少用

eta[默认0.3]:类似于learning rate参数,通过减少每一步的权重,可以提高模型的鲁棒性,常用的值为0.2,0.3

max_depth[默认6]:这个值为树的最大深度,max_depth越大,模型会学到更具体更局部的样本,常用的为6.

gamma[默认为0]: gamma为指定了节点分裂所需要的最小损失函数下降值,这个参数的值越大,算法越保守,这个参数的值和损失函数息息相关。

subsample[默认为1]:这个参数控制对于每棵树,随机采样的比例,减少这个参数的值,算法会更加保守,避免过拟合,但是如果这个值设置的过小,它可能会导致前拟合,常用的值为0.7-1

colsample_bytree[默认1]:用来控制每棵树随机采用列数的占比,常用是0.7-1。

3: 学习目标参数

objective[默认reg:linear]:这个参数定义需要被最小化的损失函数,binary:logistic 而分类的逻辑回归,返回预测的概率,multi:softmax使用softmax的多分类器,返回预测的类别,这种情况下,还需要多设一个参数: num_class(类别数目)。multi: softprob 和multi: softmax参数一样,但是返回的是每个数据属于各个类别的概率。

eval_metric[默认取决于objective参数的取值]:对于有效数据的度量方法,对于回归问题,默认是rmse,对于分类问题,默认值是error,其他的值:rmse均方根误差,mae平均绝对误差,logloss负对数似然函数值,error二分类错误率,merror为多分类错误率,auc为曲线下面积。

seed[默认0]:随机树的种子,设置可以复现随机数据的结果。

参考内容:

[1] http://xgboost.apachecn.org/cn/latest/model.html

自然语言处理技术

关注微信号每天收听我们的消息

自然语言处理技术为您推送精品阅读

每天一个知识点,健康生活每一天

欢迎关注公众号学习交流

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180123G0XJJ100?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券