返回列表

3rd Place Solution: CatBoost Encoding Galore

595. Playground Series - Season 4, Episode 1 | playground-series-s4e1

开始: 2024-01-02 结束: 2024-01-31 用户画像与运营 数据算法赛

第三名解决方案:CatBoost编码大全

作者:Iqbal Syah Akbar
发布时间:2024年2月1日

好吧,经过11个月后,我终于进入了Playground系列赛的前三名。我从未想过今年的首场比赛会以如此疯狂的方式结束。毕竟,在3600支队伍中获得第三名,这比我去年取得的成就高出了好几个层次。

事不宜迟,让我来分享我的做法。

特征工程

  1. 我对一些特征应用了TF-IDF向量化,然后用TruncatedSVD进行分解(感谢@arunklenin)。但与大多数人不同,我尝试构建了一个类,以便能在管道中实现它,并对不同的特征集进行不同类型的向量化和分解。
  2. 我基于@aspillai这个笔记本创建了新特征。但没有包含缩放和IsSenior特征。我也为自己修改了Sun_Geo_Gend_Sal特征。从现在开始我将它称为AllCat
  3. 我创建了一个名为ZeroBalance的新特征,用于指示客户是否零余额。
  4. 最后,我将EstimatedSalaryAge都乘以100和10后转换为整数。为什么?你很快就会知道主要原因。但一个有趣的副作用是,仅仅将Age乘以10,与@aspillai笔记本中的分箱代码配对使用时,就会提升效果(这相当于只将Age除以2进行分箱)。

编码

在进入集成学习之前,我想先讨论编码,这是获得高性能的关键。我在本次比赛中使用了三种编码器:CatBoost内置编码器、来自category-encoders库的CatBoost编码器和M-Estimate编码器。第一个原因很明显,第二个是因为我还想将CatBoost编码应用于其他估计器。至于第三个,是因为XGBoost和LightGBM不太喜欢过多的CatBoost编码。不过我不会过多解释它,因为它对高性能的贡献不是主要的。

现在,让我们来看看我编码了哪些特征。实际上,让我重新表述这句话。让我们看看我没有编码哪些特征。在原始特征集中,只有BalanceHasCrCard是未编码的特征。其余的?几乎全部编码了。这包括像EstimatedSalaryAge这样的浮点特征,现在你知道我为什么要把它们转换为整数了。另外,还记得我之前提到的特征工程AllCat吗?那是因为我将几乎所有计划编码的特征都连接到了那个特征中,除了IsActiveMember,因为我还编码了IsActive_by_CreditCard。总共有12个特征我进行了编码…或者你以为如此。

还记得TF-IDF向量化和SVD分解吗?其实你也可以对它们进行编码!只需将我对EstimatedSalaryAge所做的操作同样应用到分解结果上即可。需要注意的是,我只对Surname的4个SVD分解组件进行了编码,尽管我还在AllCat和其他一些特征上进行了向量化和分解。

关于编码的另一个重要点是,CatBoost编码实际上非常关注数据集的顺序。嗯,默认情况下不是这样,但你可以这样设置。事实上,category-encoders的CatBoostEncoder会以不同方式处理不同顺序的数据。为了让CatBoost在编码特征时不允许数据集置换,你必须将has_time参数设置为True。那么最佳的数据集顺序是什么?当连接原始数据集和比赛训练数据集时,你必须将原始数据集放在比赛数据集之前。这样会在本次比赛中获得最佳结果。

集成学习

我在本次比赛中使用了7个模型。

  1. 逻辑回归是性能最低的模型,但也是在实验哪些特征需要用category-encoders的CatBoostEncoder进行编码的最佳模型。在某种程度上,它可以作为指示器,告诉你哪些特征需要为CatBoost进行编码。
  2. 对于神经网络,我使用了输入层->32个LeakyReLU->64个LeakyReLU->16个LeakyReLU->4个LeakyReLU->1个Sigmoid的架构,使用AdamW优化器。它使用的编码与逻辑回归相同。此外,这是唯一一个我没有应用任何向量化的模型。
  3. XGBoost对不同特征集使用了CatBoost编码器和M-Estimate编码器,我使用Optuna进行超参数优化。向量化的应用也涉及4个特征,最大特征数为500,分解组件为3个。
  4. LightGBM在预处理方面与XGBoost类似。
  5. 3个CatBoost模型各自使用不同的bootstrap类型:无bootstrap、贝叶斯和伯努利,使用完全相同的预处理:对2个特征进行向量化,最大特征数为1000,分解组件为4个。它们都有超过0.902的CV分数。我没有进行任何超参数优化,因为它们已经慢得像蜗牛了。

权重由岭分类器定义。如果你好奇,我在每个模型管道内实现了所有预处理,因为我在交叉验证中是个防止泄漏的狂人。

补充说明

  1. 根据我的观察,提升分数的一个方法是增加折数。因此,我使用5折进行实验,使用30折进行提交,几乎花了12小时。
  2. 我早就该发现并做的另一件事是对同一个原始数据集进行多次连接,因为连接两次实际上给了我最好的私有LB分数(也许这就是前两名所使用的黑魔法,我不知道)。
  3. 我还应用了@paddykb关于数据泄漏的后处理。
  4. 最后,你可以在这里阅读我的笔记本

感谢所有参加本次比赛的成员。希望你们能从这份总结中学到很多。另外,下次我会尝试参与讨论,因为在获奖后我不再有保持沉默的理由(除非我有很大机会获得第一名):)

同比赛其他方案