算法强化 —— XGBoost(三)

缺失值处理

真实场景中,有很多可能导致产生稀疏。如:数据缺失、某个特征上出现很多0项、人工进行one-hot编码导致大量的0
理论上,数据缺失和数值0的含义是不同的,数值0是有效的
实际上,数值0的处理方式类似缺失值的处理方式,都视为稀疏特征
在xgboost中,数值0的处理方式和缺失值的处理方式是同一的。这只是一个计算上的优化,用于加速稀疏特征的处理速度
对于稀疏特征,只需要对有效值进行处理,无效值则采用默认的分裂方向。
注意每个结点的默认分裂方向可能不同。

XGBoost中实现的方式

在xgboost算法的实现中,允许对数值0进行不同的处理。可以将数值0视作缺失值,也可以将其视作有效值。
如果数值0是有真实意义的,则建议将其视作有效值。

缺失值处理算法

输入:数据集D=(x1,y1~),(x2,y2~),...,(xN,yN~)D = {(\overrightarrow{x_1},\tilde{y_1}),(\overrightarrow{x_2},\tilde{y_2}),...,(\overrightarrow{x_N},\tilde{y_N})},其中样本xi=(xi,1,xi,2,...,xi,n)T\overrightarrow{x_i} = (x_{i,1},x_{i,2},...,x_{i,n})^T
属于当前叶节点的样本的下标集合I\mathbb{I}
属于当前叶节点,且第k维特征有效的样本的下标集合Ik=iIxk,imissing\mathbb{I}_k = {i \in \mathbb{I} | x_{k,i} \not= missing}
输出:当前叶节点最佳分裂点

算法

初始化:score0,GiIgi,HiIhiscore \leftarrow 0, G \leftarrow \sum_{i \in \mathbb{I}}g_i,H \leftarrow \sum_{i \in \mathbb{I}}h_i
遍历各维度:k = 1,…,n

先从左边开始遍历
初始化 GL0,HL0G_L \leftarrow 0,H_L \leftarrow 0
遍历各拆分点:沿着第k维,将当前有效的叶节点的样本从小到大排序,相当于所有无效特征值的样本放在最右侧,因此可以保证无效的特征值都在右子树。
然后用j顺序遍历排序后的样本下标:
GLGL+gj,HLHL+hjGRGGL,HRHHL\begin{aligned} &\mathbf{G}_{L} \leftarrow \mathbf{G}_{L}+g_{j}, \quad \mathbf{H}_{L} \leftarrow \mathbf{H}_{L}+h_{j}\\ &\mathbf{G}_{R} \leftarrow \mathbf{G}-\mathbf{G}_{L}, \quad \mathbf{H}_{R} \leftarrow \mathbf{H}-\mathbf{H}_{L} \end{aligned}
scoremax(score,GL2HL+λ+GR2HR+λG2H+λ)\text {score} \leftarrow \max \left(\text {score}, \frac{\mathbf{G}_{L}^{2}}{\mathbf{H}_{L}+\lambda}+\frac{\mathbf{G}_{R}^{2}}{\mathbf{H}_{R}+\lambda}-\frac{\mathbf{G}^{2}}{\mathbf{H}+\lambda}\right)

再从右边开始遍历
初始化GR0,HR0G_R \leftarrow 0,H_R \leftarrow 0
遍历各拆分点:沿着第k维,将当前有效的叶节点的样本从大到小排序,相当于所有无效特征值的样本放在最左侧,因此可以保证无效的特征值都在左子树。
然后用j顺序遍历排序后的样本下标:
GRGR+gj,HRHR+hjGLGGL,HLHHR\begin{aligned} &\mathbf{G}_{R} \leftarrow \mathbf{G}_{R}+g_{j}, \quad \mathbf{H}_{R} \leftarrow \mathbf{H}_{R}+h_{j}\\ &\mathbf{G}_{L} \leftarrow \mathbf{G}-\mathbf{G}_{L}, \quad \mathbf{H}_{L} \leftarrow \mathbf{H}-\mathbf{H}_{R} \end{aligned}
scoremax(score,GL2HL+λ+GR2HR+λG2H+λ)\text {score} \leftarrow \max \left(\text {score}, \frac{\mathbf{G}_{L}^{2}}{\mathbf{H}_{L}+\lambda}+\frac{\mathbf{G}_{R}^{2}}{\mathbf{H}_{R}+\lambda}-\frac{\mathbf{G}^{2}}{\mathbf{H}+\lambda}\right)
选取最大的score对应的维度和拆分点作为最优拆分点

其他优化

预排序

xgboost提出column block 数据结构来降低排序时间
每一个block代表一个属性,样本在该block中按照它在该属性的值排好序
这些block只需要在程序开始的时候计算一次,后续排序只需要线性扫描这些block即可
由于属性之间是独立的,因此在每个维度寻找划分点可以并行计算
block可以仅存放样本的索引,而不是样本本身,这样节省了大量的存储空间

缓存命中率的优化

Cache-aware预取

由于在column block中,样本的顺序会被打乱,这会使得从导数数组中获取gig_i时的缓存命中率较低。
因此xgboost提出了cache-aware预取算法,用于提升缓存命中率
xgboost会以minibatch的方式累加数据,然后在后台开启一个线程来加载需要用到的导数gig_i
这里有个这种,minibatch太大,则会引起cache miss;太小,则并行程度较低

out of score 大数据集

xgboost利用硬盘来处理超过内存容量的大数据。其中使用了下列技术
使用block 压缩技术来环节内存和硬盘的数据交换IO:数据按列压缩,并且在硬盘到内存的传输过程中被自动解压缩
数据随机分片到多个硬盘,每个硬盘对应一个预取线程,从而加大"内存-硬盘"交换数据的吞吐量

发布了96 篇原创文章 · 获赞 3 · 访问量 2526
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览