XGBoost是Kaggle上的比赛神器,近些年在kaggle或天池比赛上时常能斩获大奖,不过这样的历史正在改变!最近几年神经网络的优势开始从非结构数据向结构数据延伸,而且在一些Kaggle比赛中取得非常不错的成绩。
XGBoost很牛,不过更牛的应该是NN! 这章我们通过一个实例来说明,本实例基于相同数据,使用XGBoost和神经网络(NN)对类别数据转换为数字。XGBoost是属于Tree Model,故是否使用One-hot影响不大(通过测试,确实如此,相反,如果转换为one-hot将大大增加内存开销),所以使用xgboost的数据转换为数字后,没有再转换为one-hot编码。对神经网络(NN)而言,是否把数据转换为One-hot,影响比较大,所以使用NN的模型数据已转换为One-hot。
两种算法测试结果为表2-1。

训练及测试数据没有打乱,其中测试数据是最新原数据的10%。

2.1 XGBoost简介

2.1.1概述

XGBoost的全称是eXtreme Gradient Boosting,由很多CART(Classification And Regression Tree)树集成,其中CART是对分类决策树和回归决策树的总称。
分类决策树一般使用信息增益、信息增益率、基尼系数来选择特征的依据。CART回归树是假设树为二叉树,通过不断将特征进行分裂。比如当前树结点是基于第j个特征值进行分裂的,设该特征值小于s的样本划分为左子树,大于s的样本划分为右子树。因此,当我们为了求解最优的切分特征j和最优的切分点s,就转化为求解这么一个目标函数。

只要遍历所有特征的的所有切分点,就能找到最优的切分特征和切分点。最终得到一棵回归树。

2.1.2 主要原理

XGBoost本质上还是一个GBDT(Gradient Boosting Decision Tree),但为力争把速度和效率发挥到极致,所以叫X (Extreme) GBoosted。GBDT的原理就是所有弱分类器的结果相加等于预测值,然后下一个弱分类器去拟合误差函数对预测值的梯度(或残差)(这个梯度/残差就是预测值与真实值之间的误差)。一个弱分类器如何去拟合误差函数残差?
举一个非常简单的例子,比如我今年30岁了,但计算机或者模型GBDT并不知道我今年多少岁,那GBDT咋办呢?
(1)它会在第一个弱分类器(或第一棵树中)随便用一个年龄比如20岁来拟合,然后发现误差有10岁;
(2)在第二棵树中,用6岁去拟合剩下的损失,发现差距还有4岁;
(3)在第三棵树中用3岁拟合剩下的差距,发现差距只有1岁了;
(4)在第四课树中用1岁拟合剩下的残差,完美。
最终,四棵树的结论加起来,就是真实年龄30岁。实际工程中GBDT是计算负梯度,用负梯度近似残差。
注意,为何GBDT可以用用负梯度近似残差呢?
回归任务下,GBDT 在每一轮的迭代时对每个样本都会有一个预测值,此时的损失函数为均方差损失函数,表达式如下:

那此时的负梯度是这样计算的,具体表达式如下:

所以,当损失函数选用均方损失函数是时,每一次拟合的值就是(真实值 - 当前模型预测的值),即残差。此时的变量是,即“当前预测模型的值”,也就是对它求负梯度。
更多详细内容可参考:https://blog.csdn.net/v_july_v/article/details/81410574

2.1.3 主要优点

(1)目标表达式:
XGBoost优化了GBDT的目标函数。一方面,在GBDT的基础上加入了正则项,包括叶子节点的个数和每个叶子节点输出的L2模的平方和,正则项可以控制树的复杂度,让模型倾向于学习简单的模型,防止过拟合;另外,XGBoost还支持线性分类器,传统的GBDT是以CART算法作为基学习器。
(2)使用Shrinkage:
对每棵树的预测结果采用了shrinkage,相当于学习率,降低模型对单颗树的依赖,提升模型的泛化能力。
(3)采用列采样:
XGBoost借助了随机森林的优点,采用了列采样,进一步防止过拟合,加速训练过程,而传统的GBDT则没有列采样。
(4)优化方法:
XGBoost对损失函数的展开采用了一阶梯度和二阶梯度,而传统的GBDT只采用了一阶梯度。
(5)增益计算:
对分裂依据进行了优化。不同于CART算法,XGBoost采用了新的基于一阶导数和二阶导数的统计信息作为树的结构分数,采用分列前的结构与分裂后的结构得分的增益作为分裂依据,选择增益最大的特征值作为分裂点,替代了回归树的误差平方和。
(6)最佳增益节点查找:
XGBoost在寻找最佳分离点的方式上采用了近似算法,基于权重的分位数划分方式(权重为二阶梯度)。主要是对特征取值进行分桶,然后基于桶的值计算增益。
(7)预排序。
在寻找最佳增益节点时,将所有数据放入内存进行计算,得到预排序结果,然后在计算分裂增益的时候直接调用。
(8)缺失值处理
对于特征的值有缺失的样本,Xgboost可以自动学习出他的分裂方向。Xgboost内置处理缺失值的规则。
(9)支持并行。
众所周知,Boosting算法是顺序处理的,也是说Boosting不是一种串行的结构吗?怎么并行的?注意XGBoost的并行不是tree粒度的并行。XGBoost也是一次迭代完才能进行下一次迭代的(第t次迭代的代价函数里包含)。XGBoost的并行式在特征粒度上的,也就是说每一颗树的构造都依赖于前一颗树。

2.1.4 XGBoost的模型参数

XGBoost使用字典的方式存储参数,主要参数有如下这些:

安装XGBoost建议使用conda命令。如:conda install py-xgboost=0.90

2.2 NN简介

使用的神经网络结构如下图所示

图2-1 神经网络结构
本实例使用的神经网络结构比较简单,共4层,除输入、输出层外,中间是两个全连接层。输入层1183个节点,这个正好是特征转换为one-hot后的元素个数,第1个隐含层的节点是1000,激活函数为relu,第2个隐含层的节点数为500,激活函数为relu,输出层1个节点,激活函数为sigmoid。

2.3 数据集简介

这里使用德国Rossmann超市2013、2014、2015三年的销售数据,具体数据文件包括:
train.csv-包括销售在内的历史数据
test.csv-测试数据(不包括销售)
store.csv-有关商店的补充信息
这些数据可从这里下载:https://www.kaggle.com/c/rossmann-store-sales/data
1、train.csv-包括销售在内的历史数据,共有9列,每列的含义如下:
date(日期):代表存储期
DayOfWeek(星期几):7表示周日,6表示周六以此类推
store(商店):每个商店的唯一ID
sale(销售):特定日期的营业额(这是您的预期)
customer(客户):特定日期的客户数量
open(开):为对存储是否被打开的指示:0 =关闭,1 =开
promo(促销):表示商店当天是否在进行促销
StateHoliday(州假日):通常,除州外,所有商店都在州法定假日关闭。请注意,所有学校在公共假日和周末都关闭。a =公共假期,b =复活节假期,c =圣诞节,0 =无
SchoolHoliday(学校假日):指示(商店,日期)是否受到公立学校关闭的影响
(1)导入数据

(2)查看前5行数据。

(3)查看是否有空值

Store 0
DayOfWeek 0
Sales 0
Customers 0
Open 0
Promo 0
StateHoliday 0
SchoolHoliday 0
dtype: int64
(4)查看各特征的不同值

共有几年的数据: [2015 2014 2013]
共有几种促销方法: [1 0]
2、store.csv数据集简介
StoreType- 区分4种不同的商店模型:a,b,c,d
Assortment分类 -描述分类级别:a =基本,b =额外,c =扩展
CompetitionDistance-距离最近的竞争对手商店的距离(以米为单位)
CompetitionOpenSince [Month / Year] -给出最近的竞争对手开放的大概年份和月份。
Promo促销 -表示商店当天是否在进行促销
Promo2 -Promo2是某些商店的连续和连续促销:0 =商店不参与,1 =商店正在参与
Promo2Since [年/周] -描述商店开始参与Promo2的年份和日历周。
PromoInterval-描述启动Promo2的连续间隔,并指定重新开始促销的月份。例如,“ Feb,May,Aug,Nov”表示该商店的每一轮始于该年任何一年的2月,5月,8月,11月

2.4使用Xgboost算法实例

2.4.1 读取数据

(1)导入模块

(2)定义数据预处理函数

(3)读取数据

2.4.2 预处理数据

(1)导入模块

(2)读取处理后的文件

(3)定义预处理store数据函数

(4)生成训练数据

2.4.3 保存预处理数据

(1)把各类别特征转换为整数,并保存为pickle文件

2.4.4 采样生成训练与测试数据

(1)读取数据

(2)生成训练与测试集

(3)定义采样函数

(4)采样数据

2.4.5 构建模型

(1)导入模块

(2)构建xgboost模型

2.4.6 训练模型

运行结果如下:
[2980] train-rmse:0.148366
[2981] train-rmse:0.148347
[2982] train-rmse:0.148314
[2983] train-rmse:0.148277
[2984] train-rmse:0.148238
[2985] train-rmse:0.148221
[2986] train-rmse:0.148218
[2987] train-rmse:0.148187
[2988] train-rmse:0.148182
[2989] train-rmse:0.148155
[2990] train-rmse:0.148113
[2991] train-rmse:0.148113
[2992] train-rmse:0.148067
[2993] train-rmse:0.148066
[2994] train-rmse:0.148064
[2995] train-rmse:0.148062
[2996] train-rmse:0.148048
[2997] train-rmse:0.148046
[2998] train-rmse:0.148046
[2999] train-rmse:0.148041
Result on validation data: 0.14628885960491078

2.5 使用NN算法实例

2.5.1 预处理数据

导入数据、对数据进行预处理,这些与2.4小节中的2.4.1、2.4.2一样,接下来对个特征先转换为数字,然后转换为one-hot编码,并保存。
(1)把数据转换为one-hot编码

(2)保存数据

2.5.2 生成训练数据

(1)读取数据

(2)生成训练数据

(3)定义采样函数

(4)通过采样生成训练数据

2.5.3 构建神经网络模型

(1)导入模块

(2)定义Model类

(3)构建神经网络

2.5.4 训练模型

运行结果:
Fitting NN...
Train on 200000 samples, validate on 84434 samples
Epoch 1/10
200000/200000 [==============================] - 12s 60us/sample - loss: 0.0121 - val_loss: 0.0142
Epoch 2/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0080 - val_loss: 0.0104
Epoch 3/10
200000/200000 [==============================] - 11s 53us/sample - loss: 0.0071 - val_loss: 0.0100
Epoch 4/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0064 - val_loss: 0.0099
Epoch 5/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0059 - val_loss: 0.0098
Epoch 6/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0055 - val_loss: 0.0103
Epoch 7/10
200000/200000 [==============================] - 11s 55us/sample - loss: 0.0051 - val_loss: 0.0100
Epoch 8/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0047 - val_loss: 0.0099
Epoch 9/10
200000/200000 [==============================] - 11s 53us/sample - loss: 0.0045 - val_loss: 0.0102
Epoch 10/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0042 - val_loss: 0.0100
Result on validation data: 0.10825838109273625

接下来将用更多实例,从多个角度比较NN与传统ML的比较,带EE(Entity Embedding)的NN与不带NN的比较,带EE的传统ML与不带EE的传统ML,以及EE在ML的顶级应用(如推荐算法、预测等问题上的使用)。
EE就像一座桥梁,把结构化数据与NN(或深度学习算法)连接在一起,大大发挥了NN在处理结构化数据方面的潜能(即NN强大的学习能力),深度学习将彻底改变传统机器学习。