Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >推荐系统中传统模型——LightGBM + LR融合

推荐系统中传统模型——LightGBM + LR融合

作者头像
悟乙己
发布于 2021-12-07 06:28:31
发布于 2021-12-07 06:28:31
1.8K00
代码可运行
举报
文章被收录于专栏:素质云笔记素质云笔记
运行总次数:0
代码可运行

笔者最近再学习腾讯广告算法大赛,发现一些选择会用GBDT来进行“降维”与特征工程,有提分点,于是乎也来看看。之前的一篇跟LightGBM相关的文章:python - 机器学习lightgbm相关实践

这里可以直接跑通的github:wangru8080/gbdt-lr

1 GBDT + LR原理

参考:GBDT+LR算法解析及Python实现

1.1 CTR常见流程

GBDT+LR 使用最广泛的场景是CTR点击率预估,即预测当给用户推送的广告会不会被用户点击。

点击率预估模型涉及的训练样本一般是上亿级别,样本量大,模型常采用速度较快的LR。但LR是线性模型,学习能力有限,此时特征工程尤其重要。现有的特征工程实验,主要集中在寻找到有区分度的特征、特征组合,折腾一圈未必会带来效果提升。GBDT算法的特点正好可以用来发掘有区分度的特征、特征组合,减少特征工程中人力成本。

从知乎https://zhuanlan.zhihu.com/p/29053940上看到了一个关于CTR的流程,如下图所示:

如上图,主要包括两大部分:离线部分、在线部分,其中离线部分目标主要是训练出可用模型,而在线部分则考虑模型上线后,性能可能随时间而出现下降,弱出现这种情况,可选择使用Online-Learning来在线更新模型.

1.2 RF/GBDT哪个更适合

RF也是多棵树,但从效果上有实践证明不如GBDT。且GBDT前面的树,特征分裂主要体现对多数样本有区分度的特征;后面的树,主要体现的是经过前N颗树,残差仍然较大的少数样本。优先选用在整体上有区分度的特征,再选用针对少数样本有区分度的特征,思路更加合理,这应该也是用GBDT的原因。

1.3 GBDT + LR比 FM进步在哪?

(读论文)推荐系统之ctr预估-LR与GBDT+LR模型解析

特征交叉而提出的FM和FFM虽然能够较好地解决数据稀疏性的问题,但他们仍停留在二阶交叉的情况。

Facebook提出了一种利用GBDT(Gradient Boosting Decision Tree)自动进行特征筛选和组合,进而生成新的离散特征向量,再把该特征向量当作LR模型输入,预估CTR的模型结构。

由于决策树的结构特点,事实上,决策树的深度就决定了特征交叉的维度。如果决策树的深度为4,通过三次节点分裂,最终的叶节点实际上是进行了3阶特征组合后的结果,如此强的特征组合能力显然是FM系的模型不具备的。但由于GBDT容易产生过拟合,以及GBDT这种特征转换方式实际上丢失了大量特征的数值信息,因此我们不能简单说GBDT由于特征交叉的能力更强,效果就比FM或FFM好(事实上FFM是2015年提出的)。在模型的选择和调试上,永远都是多种因素综合作用的结果。

GBDT+LR比FM重要的意义在于,它大大推进了特征工程模型化这一重要趋势,某种意义上来说,之后深度学习的各类网络结构,以及embedding技术的应用,都是这一趋势的延续。

1.3 树模型对稀疏离散特征,处理较差

参考:

GBDT只是对历史的一个记忆罢了,没有推广性,或者说泛化能力。

但这并不是说对于大规模的离散特征,GBDT和LR的方案不再适用,感兴趣的话大家可以看一下参考文献2和3,这里就不再介绍了。

2 LightGBM + LR融合案例

一段核心代码,整体流程为:

源数据 -> 标准化 -> 训练LGM模型 -> 预测训练集+验证集的每个样本落在每棵树的哪个节点上 -> LGB的节点特征合并成为新的训练集/验证集

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def gbdt_ffm_predict(data, category_feature, continuous_feature):
    # 离散特征one-hot编码
    print('开始one-hot...')
    for col in category_feature:
        onehot_feats = pd.get_dummies(data[col], prefix = col)
        data = pd.concat([data, onehot_feats], axis = 1)
    print('one-hot结束')
    

    feats = [col for col in data if col not in category_feature] # onehot_feats + continuous_feature
    tmp = data[feats]
    train = tmp[tmp['Label'] != -1]
    target = train.pop('Label')
    test = tmp[tmp['Label'] == -1]
    test.drop(['Label'], axis = 1, inplace = True)
    
    # 划分数据集
    print('划分数据集...')
    x_train, x_val, y_train, y_val = train_test_split(train, target, test_size = 0.2, random_state = 2018)

    print('开始训练gbdt..')
    gbm = lgb.LGBMRegressor(objective='binary',
                            subsample= 0.8,
                            min_child_weight= 0.5,
                            colsample_bytree= 0.7,
                            num_leaves=100,
                            max_depth = 12,
                            learning_rate=0.05,
                            n_estimators=10,
                            )

    gbm.fit(x_train, y_train,
            eval_set = [(x_train, y_train), (x_val, y_val)],
            eval_names = ['train', 'val'],
            eval_metric = 'binary_logloss',
            # early_stopping_rounds = 100,
            )
    model = gbm.booster_
    print('训练得到叶子数')
    gbdt_feats_train = model.predict(train, pred_leaf = True)  # 获得训练集的各颗树的节点数(10棵树,每棵树100个叶子节点)
    train.shape,gbdt_feats_train.shape  # ((1599, 13104), (1599, 10))13104维度 降维到10维

    gbdt_feats_test = model.predict(test, pred_leaf = True)    # 获得验证集的各颗树的节点数(10棵树,每棵树100个叶子节点)
    gbdt_feats_name = ['gbdt_leaf_' + str(i) for i in range(gbdt_feats_train.shape[1])]
    df_train_gbdt_feats = pd.DataFrame(gbdt_feats_train, columns = gbdt_feats_name) 
    df_test_gbdt_feats = pd.DataFrame(gbdt_feats_test, columns = gbdt_feats_name)

    print('构造新的数据集...')
    tmp = data[category_feature + continuous_feature + ['Label']]
    train = tmp[tmp['Label'] != -1]
    test = tmp[tmp['Label'] == -1]
    train = pd.concat([train, df_train_gbdt_feats], axis = 1)
    test = pd.concat([test, df_test_gbdt_feats], axis = 1)
    data = pd.concat([train, test])
    del train
    del test
    gc.collect()

    # 连续特征归一化
    print('开始归一化...')
    scaler = MinMaxScaler()
    for col in continuous_feature:
        data[col] = scaler.fit_transform(data[col].values.reshape(-1, 1))
    print('归一化结束')

    data.to_csv('data/data.csv', index = False)
    return category_feature + gbdt_feats_name

先来看一下LGBMClassifier,参考:lightgbm.LGBMClassifier 如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
classlightgbm.LGBMClassifier(boosting_type='gbdt', num_leaves=31, max_depth=- 1, learning_rate=0.1, n_estimators=100, subsample_for_bin=200000, objective=None, class_weight=None, min_split_gain=0.0, min_child_weight=0.001, min_child_samples=20, subsample=1.0, subsample_freq=0, colsample_bytree=1.0, reg_alpha=0.0, reg_lambda=0.0, random_state=None, n_jobs=- 1, silent=True, importance_type='split', **kwargs)

其中:

  • n_estimators - 树的棵树,相当于主成分,多少个主成分一样
  • num_leaves,叶子节点
  • max_depth (int, optional (default=-1)) – Maximum tree depth for base learners,树的深度

model.predict(train, pred_leaf = True)这里通过pred_leaf(pred_leaf (bool, optional (default=False)) – Whether to predict leaf index.)就可以预测每个样本在叶子节点的位置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
train.shape,gbdt_feats_train.shape  
# ((1599, 13104), (1599, 10))  

gbdt_feats_train
>>> array([[ 2,  9,  3, ...,  2, 14,  4],
		       [ 1,  8,  1, ..., 20, 16,  1],
		       [18, 35, 39, ..., 38, 24, 29],
		       ...,
		       [44, 18, 13, ...,  8, 17, 23],
		       [23, 20, 17, ...,  4,  0, 30],
		       [20, 24,  0, ..., 28, 22, 36]])

从13104维度 降维到10维(树的棵树),然后每个样本标记的,在10棵树的叶子位置(每个样本(1599)在10颗树的叶子(100片叶子)节点的编号)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/12/28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【入职篇】入职一家新公司,如何快速熟悉代码?
这里面既要熟悉公司的企业文化、产品业务、技术框架、系统代码,还要处理好身边的同事关系。。。。
微观技术
2022/09/28
4440
【入职篇】入职一家新公司,如何快速熟悉代码?
认真聊聊写博客这件事
结交新朋友、面试、晋升、与Leader汇报工作、撩妹、哄老婆。。。沟通表达能力与我们的生活是息息相关的。
童欧巴
2020/06/04
2660
关于写作这件事
在2022的总结中,提到了持续写作与输出的事,不少人留言问如何做到日更,有那么多素材么?还有人提到持续输出的目的是什么?是为了流量和副业吗?本文就聊聊这个话题吧,也给越来越多写公众号的小伙们一些参考。
CKL的思考
2023/02/01
2930
三板斧使你走上人生巅峰
在我目前的认知里,我觉得未来有三个技能是需要掌握的,分别是:写作、编程、理财。我相信如果这三个技能都掌握了,我相信你里财富自由之路已经不远了。 想要走上财富自由,主要看你的「睡后」收入,就是在你睡觉的时候还有的输入,比如你录视频卖、写书、做自媒体写文章、理财等等,程序员如果增加「睡后」输入,请看 Stromzhang 的 这篇文章 。 这些都会让你在你睡觉了之后还有收入,跟你上班出售自己的时间相比,你花在这些能增加「睡后」收入的时间可以重复卖这些时间。 比如一个作家花一年的时间写了一本书,可以畅销十年;那些
桃翁
2018/06/27
4780
写作即思考:工程师如何用技术文档完成逻辑的『认知复利』
在程序员的世界里,人们常说“Talk is cheap, show me the code”,但随着生成式AI的普及,“Code is cheap, show me the prompt”正悄然改写规则。技术文档写作,这一传统上被视为“苦差事”的能力,反而成为区分工程师专业素养的分水岭——它不仅是知识传递的工具,更是锤炼逻辑思维、提升表达能力的绝佳途径。
用户2755790
2025/04/08
990
【Dev Club 话题讨论】程序员的成长离不开哪些软技能?
Dev Club 是一个交流移动开发技术,结交朋友,扩展人脉的社群,成员都是经过审核的移动开发工程师。定期会举行嘉宾分享,话题讨论等活动。 本期讨论话题为:程序员的成长离不开哪些软技能? 首先,什么是软技能? 软技能就是激活人资的能力,即是调动别人的资源和知识的能力以及调动自己知识进行创造性思维的能力!软技能能力值越高,处理事情的能力就越强,它是衡量一个人处理事情能力的量表!这里的资源指:知识和朋友。软技能实际上是指那些“不易看见的技能”,是一个人“激发自己潜能和通过赢得他人认可和合作放大自己的资源,以获得
腾讯Bugly
2018/03/23
7400
技术写作 —— 一种独特的倒逼成长的方式
技术写作的目的和意义是什么?在我看来,技术写作是 一种独特的倒逼成长的方式,它能帮助我们在思维、表达、自律等多个方面实现成长。
陈明勇
2024/07/25
3332
技术写作 —— 一种独特的倒逼成长的方式
程序员自我修练-提高写代码的能力
首先让我们看一看刚入软件公司会出现的情况: 1. 你可能会常常发现,写了一段代码后,编译程序时是一大堆的出错 (原因:语法不熟)
lyb-geek
2018/12/07
2.2K0
「 牛逼的程序员 」+「 会写作 」= ?
我在之前的文章中分享过一个观点,咱们程序员除了代码之外,还必须得会营销自己,建立个人的影响力。
奎哥
2019/08/14
6040
书终于交稿了,聊聊写技术书这件事
这两天刚刚把与出版社签约的书交稿,虽然内容还在与编辑逐步勘定、修改。但大块头的事基本上已经完成。细心的朋友可能看到最近公众号“程序新视界”更新没那么勤了,就是因为忙这事。今天就聊聊写书过程的一些杂谈。
程序新视界
2019/11/28
6290
「ChatGPT」一夜之间“火爆出圈“【杞人忧天 or 未雨绸缪】
💂作者简介: THUNDER王,一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读,同时任汉硕云(广东)科技有限公司ABAP开发顾问。在学习工作中,我通常使用偏后端的开发语言ABAP,SQL进行任务的完成,对SAP企业管理系统,SAP ABAP开发和数据库具有较深入的研究。 💅文章概要: ChatGPT"一夜爆红",本文将深耕其中的本质,带大家好好了解一下未来这场暗潮汹涌的人与AI之间的联系——竞争or合作? 🤟每日一言: 你可以遗憾,但是你绝对不能后
THUNDER王
2023/02/23
4310
「ChatGPT」一夜之间“火爆出圈“【杞人忧天 or 未雨绸缪】
程序员转型的无限可能:探索代码外的精彩人生
在当今快速发展的科技行业,程序员的职业发展路径不再局限于传统的技术管理或产品经理角色。随着技术的不断演进和市场需求的变化,程序员可以探索多种转型方向,开辟新的职业道路。本文将深入探讨程序员可转型的领域、所需技能,以及如何利用已有的技术背景实现平滑过渡。同时,我将强调保持活力和开放心态的重要性,以及分享一些成功案例,激励更多程序员勇敢迈出转型的第一步。
码事漫谈
2025/01/08
2100
程序员转型的无限可能:探索代码外的精彩人生
年轻程序员如何快速成长
最近公司招聘了一批初级前端工程师,招聘之后就是开始培训和实习指导,培训过程中,思考了一些问题,包括如何更好的培训 指导 以及管理新人。也思索了新人程序员自己应该如何快速成长。
用户3158888
2018/09/04
2530
年轻程序员如何快速成长
一个合格的程序员,需要哪些必备技能?
但是,除了基本的编程开发能力,其他方面的能力也是体现一个程序员的能力的很重要因素。
java思维导图
2019/11/04
4440
「面向信仰编程」Draven 专访:像写代码一样,用树形的结构写文章
Draven 是来自 Shopee Engineering Infrastructure 团队的后端工程师。在工作之余,他还拥有另一重身份——技术写作者。
Shopee技术团队
2022/04/23
7100
「面向信仰编程」Draven 专访:像写代码一样,用树形的结构写文章
黄勇:真正的开源并非只是代码的开源,而是思想的开源
【编者按】一个普通的技术人讲述不平凡的技术人生路。黄勇,在工作十年后,写了一本书:《架构探险——从零开始写Java Web框架》,这本书是给他十年技术路的最好礼物,今天我们有幸采访了黄勇,请他谈一谈他的一路走来,也就技术人员发展的一些问题进行讨论,以及分享他在研发管理、敏捷开发方面的研究。 本文内容很丰富,如果能够用心花时间读一读,不仅对你的IT职业生涯、技术积累等有所帮助,也会产生一种前行的推动力,因为成功的人依然在努力。也请那些在拼搏的IT人,请继续「相信梦想的力量」。 在Web开发方面,Java经历了
CSDN技术头条
2018/02/09
1.2K0
黄勇:真正的开源并非只是代码的开源,而是思想的开源
解析篇 | 毕业就拿15K!最全的应届前端入职指南
工欲善其事,必先利其器 (。・∀・)ノ゙嗨,小伙伴们 你现在收看的是腾讯NEXT学位和拉勾网联合出品的 互联网5大职业解析 — 程序员篇 希望能帮你了解未来的职场全貌~ 以下正文 程序员真的很厉害 如
腾讯NEXT学位
2018/05/14
1.2K0
00后程序员摸爬滚打近一年,为学弟学妹们总结出了以下 7 条人生建议(建议收藏)
        各位学弟学妹们大家好,我是一名出生于千禧年的00后程序员,因为个人极特殊原因,现已毕业并在职场中摸爬滚打一年。在社会近一年的不断探索中,让我明白了很多人生哲理,看透了很多人间现实。借助这次分享,我梳理了以下几个方面的主题内容,希望对你们有所帮助,在前往优秀的道路上少走弯路。
大数据梦想家
2022/05/10
7220
00后程序员摸爬滚打近一年,为学弟学妹们总结出了以下 7 条人生建议(建议收藏)
一个工作三年左右的Java程序员跟大家谈谈从业心得
貌似这一点适应的行业最广,但是我可以很肯定的说:当你从事web开发一年后,重新找工作时,才会真实的感受到这句话。 工作第一年,往往是什么都充满新鲜感,什么都学习,冲劲十足的一年;WEB行业知识更新特别快,今天一个框架的新版本,明天又是另一个新框架,有时往往根据项目的需要来不断学习新东西;所有,很多时候感觉,自己用过的东西真多呀!但是真正深入研究的东西却不多。 面试,是跳槽后第一个需要面对的问题;而且不同公司面试的着重点不同;但是却有一个共同点:Java基础是必考的。 工作第一年,可能问你String对象创建
Java高级架构
2018/04/19
1.1K0
7年iOS架构师-- 告诉你坚持写博客对我们有什么好处
1.今天来谈谈,写博客对我的益处,说起写博客,其实我写博客的时间不长,也就10来个月时间;
原来是泽镜啊
2018/06/29
8252
推荐阅读
相关推荐
【入职篇】入职一家新公司,如何快速熟悉代码?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验