初学CatBoost模型——特性、原理、目标编码、调参
参考资料
- https://www.codenong.com/cs106234234/ CatBoost官方教程:调参
- https://cloud.tencent.com/developer/article/1547842 【ML】一文详尽系列之CatBoost
- https://catboost.ai/docs/features/training-on-gpu.html?lang=en catboost支持GPU
- https://zhuanlan.zhihu.com/p/102570430 catboost完全指南
- https://www.zhihu.com/question/311641149/answer/593286799 oblivious tree在机器学习中有什么用? - 李大猫的回答 - 知乎
CatBoost简介
- 属于Boosting算法之一,GBDT的一种改进实现
- 是一种基于对称决策树(oblivious trees)算法的参数少、支持类别型变量和高准确性的GBDT框架,
- 痛点:高效合理地处理类别型特征,另外是处理梯度偏差(Gradient bias)以及预测偏移(Prediction shift)问题,提高算法的准确性和泛化能力。
CatBoost主要有以下五个特性:
- 无需调参即可获得较高的模型质量
- 支持类别型变量,无需对非数值型特征进行预处理
- 快速、可扩展的GPU版本,可以用基于GPU的梯度提升算法实现来训练你的模型,支持多卡并行
- 提高准确性,提出一种全新的梯度提升机制来构建模型以减少过拟合
- 预测速度快
了解类别型特征
类别型变量(Categorical features)
- 特征值是离散的集合并且相互比较并无意义的变量,比如用户的ID、产品ID、颜色等。
- 无法在二叉决策树中直接使用,需要onehot、labelencode等
低维的特征,One-hot encoding
目前广泛用于低势的类别特征的处理方法,适用于类别个数有限的特征。
在高势特征当中,进行折中: 是可以将类别分组成有限个的群体再进行 One-hot encoding
- TS:目标变量统计进行分组,目标变量统计用于估算每个类别的目标变量期望值
- 甚至有人直接用TS作为一个新的数值型变量来代替原来的类别型变量。重要的是,可以通过对TS数值型特征的阈值设置,基于对数损失、基尼系数或者均方差,得到一个对于训练集而言将类别一分为二的所有可能划分当中最优的那个。
- 在LightGBM当中,类别型特征用每一步梯度提升时的梯度统计(Gradient Statistics,以下简称GS)来表示。虽然为建树提供了重要的信息,但是这种方法有以下两个缺点:
- 增加计算时间,因为需要对每一个类别型特征,在迭代的每一步,都需要对GS进行计算;
- 增加存储需求,对于一个类别型变量,需要存储每一次分离每个节点的类别
为了克服这些缺点,LightGBM以损失部分信息为代价将所有的长尾类别归位一类,作者声称这样处理高势特征时比起 One-hot encoding还是好不少。不过如果采用TS特征,那么对于每个类别只需要计算和存储一个数字。
了解 Target statistics (目标变量统计)
主要学习文章: https://zhuanlan.zhihu.com/p/136174936( 目标编码)
用类别对应的标签的期望来代替原始的类别,所谓的期望,简单理解为均值(编码)即可。
简称为TS.
贪心TS(Target statistics)
最直接地用训练样本当中相同类别的数据对应目标变量y的平均值.
(举个例子吧,比如有10个样本,对应的某个类别特征是:A A A A A B B B B B,则A转换为greedy ts的形式,则要先看A对应的标签y是啥情况,假设A A A A A对应的标签为 1 1 1 0 1,则按照上面的公式为 (1*1+1*1+1*1+1*0+1*1)/5=0.8 )。
当然这种方式容易过拟合与训练集,极端的例子,假设某个类别特征为个数, 那么直接拟合为100%。又称为标签泄露了,因此这种编码方式基本不用了。
留出 TS (holdout TS)
留出TS,就是将训练集一分为二,采用新的计算公式,这样能够满足同分布的问题。
留一法 TS
初看起来,留一TS(leave-one-out TS)能够非常好地工作:
- 并没有预防目标泄露。
打分函数和损失函数
打分函数是xgboost对损失函数的处理在树的分裂过程中的表现,这也是后xgboost时代,gbdt算法的一个比较大的改变,基树不再是单纯的cart树使用gini进行分裂而是使用上面的梯度信息进行分裂的指导。
打分函数:catboost实现了XGBoost的打分函数的形式,也实现了原始的打分函数,同时也创造了另外四种的启发式的打分函数。
缺失值处理
catboost处理缺失值的方法很kaggle,其实就和平常比赛的时候把缺失值替换为9999,-9999一个意思,这里简单使用max和min其实并不是很好,你在训练集指定的max和min可能在测试集存在更大的max值或者更小的min值。
防止过拟合
Catoost除了增加了正则项来防止过拟合,还支持行列采样的方式来防止过拟合。
- 列采样: 正常的采样,参数为colsample_bylevel
- 行采样:
- 贝叶斯采样:每一个样本的权重按照[0, 1]区间内随机生成一个数字a,然后权重w = a^t
- 这里t越大则每一个样本的权重越小,相当于xgboost的subsample的程度越深。
- 随机赋权模式: 这里catboost是针对每一个样本进行随机赋权;
- 贝叶斯采样:每一个样本的权重按照[0, 1]区间内随机生成一个数字a,然后权重w = a^t
Catboost的基学习器
catboost与xgboost的level-wise以及lightgbm的leaf-wise不同,catboost的基学习器使用的是完全对称二叉树(实际上catboost实现了多种树的生长方式):
- 完全对称二叉树: 逐level构建树,直到达到指定的深度;在每次迭代中,选取每层中最优的一种分裂方式,以相同的该种方式进行分裂树的所有叶子结点,保持完全二叉树的结构。
- 深度(同xgb的level-wise):逐级构建,直至最大深度;在每次迭代中,将拆分树的所有非终端的叶子,每片叶子按条件进行分割,损失改善最佳
- 损失指南(lossguide,同lgb的leaf-wise):逐叶构建一棵树,直到达到指定的最大叶数;在每次迭代中,将损失最佳的非终端叶子结点进行拆分。
对比xbg、lgb
- xgb:按层分裂,待分裂层的所有节点各自按照自己的最大增益进行分裂,不统一
- lgb:按叶子分裂,计算所有待分裂的叶子节点,选取增益最大的一个进行分裂
- catboost:计算所有待分裂的叶子节点,选取增益最大的一个,叶子结点层统一进行分裂
catboost处理分类变量
默认来说,CatBoost会且仅会对所有取值nunique==2的特征进行onehot编码。
CatBoost 可赋予分类变量指标,进而通过独热最大量得到独热编码形式的结果(独热最大量:在所有特征上,对小于等于某个给定参数值的不同的数使用独热编码)。
如果在 CatBoost 语句中没有设置「跳过」,CatBoost 就会将所有列当作数值变量处理。
注意,如果某一列数据中包含字符串值,CatBoost 算法就会抛出错误。另外,带有默认值的 int 型变量也会默认被当成数值数据处理。在 CatBoost 中,必须对变量进行声明,才可以让算法将其作为分类变量处理。
catboost类别特征的处理(ordered ts)
对比:
- lgb:直方图
- catboost:主要使用统计特征对类别进行编码
下面主要介绍catboost的一种ts编码转换方式——buckets (简记为:加权累加和混合编码)
首先,按行将数据随机shuffle,并且标签也跟着一起shuffle的;
(需要特别提到的是,catboost每次生成新树的时候都会shuffle一下训练数据然后重新计算类别特征的编码值)
其次
one_hot_max_size 限制独热编码
one_hot_max_size 来决定是否对类别特征进行编码操作,当类别数量超过one_hot_max_size之后才进行编码,否则默认是2以上不再onehot;
自带特征组合,如颜色+种类组合成 “blue+dog”
CatBoost只考虑一部分combinations。在选择第一个节点时,只考虑选择一个特征,例如A。在生成第二个节点时,考虑A和任意一个categorical feature的组合,选择其中最好的。就这样使用贪心算法生成combinations。
梯度偏差的优化 (gradient bias)—— ordered boosting
原始的gbdt无行列采样,所有的base tree都在同一个完整的训练数据集上拟合,然而和rf不一样的是,gbdt中的tree都不是独立训练的,而是用上一轮的tree计算得到的负梯度为标签继续训练,这就导致了如果上一轮的tree计算产生了偏差,这个偏差会继续在下一轮累计,那么假设训练集和测试集的分布差异较大,则偏差会在base trees中疯狂累计,从而使得整个gbdt过度拟合训练集。
通过行列采样可以在一定程度上缓解这个问题,catboost不仅仅学习xgboost引入行列采样(子采样)、引入树的正则化这种从超参数层面控制过拟合程度的方面开发,更是在tree训练的过程中采用ordered boosting的方式来缓解这种过拟合。
catboost实际上是支持两种boosting模式的:
- 排序:根据这里的描述,在小型的数据集上能够提供更好的结果,但是耗时。不支持GPU。(官网给的建议是样本不超过5万可以考虑ordered的boosting type。)
- 白板:plain表示常规的gbdt的boosting模式,支持GPU
ordered boosting详细说明
https://pic2.zhimg.com/80/v2-a6681768f9e48d982552bae7e16109d5_720w.jpg
主要特点
- 在CatBoost中,我们生成训练数据集的s个随机排列。采用多个随机排列是为了增强算法的鲁棒性
- 在Odered TS中,针对每一个随机排列,计算得到其梯度,为了与Ordered TS保持一致,这里ordered boosting的排列与用于计算Ordered TS时的排列相同。(也就是说,ordered ts和ordered boosting是使用的同样的shuffle)
boosting计算流程图举例:(迭代中加入上一轮的负梯度+真实值,拟合残差)
- catboost的ordered boosint type在一些地方被称为引入了online learning的思路,啥意思呢,假设我们要计算x5的负梯度,则我们使用x1,x2,x3,x4训练一棵树,用这棵树predict出x5的预测值然后和真实值带入负梯度计算公式算出负梯度,从而作为x5的负梯度g作为下一轮的标签。 如果要计算x6的负梯度,则使用x1,x2,x3,x4,x5按照上面的方法如法炮制。
- 显然,这种计算方式将导致非常大的计算量,因此catboost内部做了一些改进,默认情况下,catboost只训练log(num_of_datapoints)个模型,而不是为每个数据点训练不同的模型。
训练log个模型的例子:
- 在第一个数据点上训练的模型用于计算第二个数据点的残差。
- 在前两个数据点上经过训练的另一个模型用于计算第三和第四数据点的残差
- 在前四个数据点上经过训练的另一个模型用于计算第5,6,7,8个数据点的残差
依次类推
其他 (调整参数bagging_temperature)
实际上,CatBoost将给定的数据集划分为随机排列,并对这些随机排列应用有序增强。
默认情况下,CatBoost创建四个随机排列。有了这种随机性,我们可以进一步停止过度拟合我们的模型。我们可以通过调整参数bagging_temperature来进一步控制这种随机性。
为什么验证集上的指标值会比训练集上的指标值更好?(如auc)
原因是,针对训练集和验证集,基于分类特征的自动生成的数字特征特征(ts)的计算方式有所不同:
- 训练数据集:随机排列,对于数据集中的每个对象,计算方式都不同;对于第i个对象,依赖于第i-1个对象的数据来计算特征
- 验证集:对数据集中的每个对象均等地计算特征,对于每个对象,使用训练数据集中所有对象的数据计算特征;它使用的信息比仅在数据集的一部分上计算的特征要多,验证集的计算的功能就更加强大,更强大带来的是更好的损耗值。
综上,由于验证集具有更加强大的功能,因此验证数据集上的损失值可能会比训练集上的损失值更好。
还有测试集:
- 测试集的类别特征是用训练集的同一个类别特征的多个编码值(ts,Target statistics)进行平均所得。
调参
- cat_features: 传入这个参数中的分类特征才能被CatBoost用他那迷人的方式处理,这个参数为空的话CatBoost和其他数据就没区别了,所以是最重要的特征!
- one_hot_max_size:catboost将会对所有unique值<=one_hot_max_size的特征进行独热处理。这个参数的调整因人而异
- learning_rate & n_estimators:这个和其他gbdt算法一样,学习率越小需要的学习器就越多。
- max_depth 的深度,这个没啥好多说
- subsample 子采样参数,在Bayesian Boosting Type不可用
- colsample_bylevel,colsample_bytree,colsample_bynode 列采样,不多说
- l2_leaf_reg: l2正则化系数
- random_strength: 每一次分裂都会有一个分数,这个参数会给分数+一个随机性,来进一步抵抗过拟合的问题。
GPU参数
- task_type
- devices (IDs of the GPU devices to use for training (indices are zero-based).)
model = CatBoostClassifier(iterations=1000,
task_type="GPU",
devices='0')
model.fit(train_data,
train_labels,
verbose=False)
安装支持GPU示例
https://catboost.ai/docs/concepts/python-installation.html GPU system requirements
应用场景
作为GBDT框架内的算法,GBDT、XGBoost、LightGBM能够应用的场景CatBoost也都适用,并且在处理类别型特征具备独有的优势,比如广告推荐领域。
优缺点
优点
- 能够处理类别特征
- 能够有效防止过拟合
- 模型训练精度高
缺点
- 对于类别特征的处理需要大量的内存和时间
- 不同随机数的设定对于模型预测结果有一定的影响