推荐系统组队学习——GBDT+LR

一、逻辑回归模型

逻辑回归是在线性回归的基础上加了一个 Sigmoid 函数(非线形)映射,使得逻辑回归成为了一个优秀的分类算法, 逻辑回归假设数据服从伯努利分布,通过极大化似然函数的方法,运用梯度下降来求解参数,来达到将数据二分类的目的。相比于协同过滤和矩阵分解利用用户的物品“相似度”进行推荐, 逻辑回归模型将问题看成了一个分类问题, 通过预测正样本的概率对物品进行排序。这里的正样本可以是用户“点击”了某个商品或者“观看”了某个视频, 均是推荐系统希望用户产生的“正反馈”行为, 因此逻辑回归模型将推荐问题转化成了一个点击率预估问题。

逻辑回归的步骤如下:

  1. 将用户年龄、性别、物品属性、物品描述、当前时间、当前地点等特征转成数值型向量
  2. 确定逻辑回归的优化目标,比如把点击率预测转换成二分类问题, 这样就可以得到分类问题常用的损失作为目标,训练模型
  3. 在预测的时候, 将特征向量输入模型产生预测, 得到用户“点击”物品的概率
  4. 利用点击概率对候选物品排序, 得到推荐列表

具体过程可由下图表示
在这里插入图片描述
逻辑回归模型的优点

  1. LR模型形式简单,可解释性好,从特征的权重可以看到不同的特征对最后结果的影响。
  2. 训练时便于并行化,在预测时只需要对特征进行线性加权,所以性能比较好,往往适合处理海量id类特征,用id类特征有一个很重要的好处,就是防止信息损失(相对于范化的 CTR 特征),对于头部资源会有更细致的描述
  3. 资源占用小,尤其是内存。在实际的工程应用中只需要存储权重比较大的特征及特征对应的权重。
  4. 方便输出结果调整。逻辑回归可以很方便的得到最后的分类结果,因为输出的是每个样本的概率分数,我们可以很容易的对这些概率分数进行cutoff,也就是划分阈值(大于某个阈值的是一类,小于某个阈值的是一类)

逻辑回归模型的缺点

  1. 表达能力不强, 无法进行特征交叉, 特征筛选等一系列“高级“操作(这些工作都得人工来干, 这样就需要一定的经验, 否则会走一些弯路), 因此可能造成信息的损失
  2. 准确率并不是很高。因为这毕竟是一个线性模型加了个sigmoid, 形式非常的简单(非常类似线性模型),很难去拟合数据的真实分布
  3. 处理非线性数据较麻烦。逻辑回归在不引入其他方法的情况下,只能处理线性可分的数据, 如果想处理非线性, 首先对连续特征的处理需要先进行离散化(离散化的目的是为了引入非线性),如上文所说,人工分桶的方式会引入多种问题。
  4. LR 需要进行人工特征组合,这就需要开发者有非常丰富的领域经验,才能不走弯路。这样的模型迁移起来比较困难,换一个领域又需要重新进行大量的特征工程。

二、GBDT模型

GBDT全称梯度提升决策树,在传统机器学习算法里面是对真实分布拟合的最好的几种算法之一,原因大概有几个,一是效果不错。二是即可以用于分类也可以用于回归。三是可以筛选特征, 所以这个模型是一个非常重要的模型。

GBDT通过多轮迭代, 每轮迭代会产生一个弱分类器, 每个分类器在上一轮分类器的残差基础上进行训练,残差指的就是当前模型的负梯度值。 GBDT对弱分类器的要求一般是足够简单, 并且低方差高偏差。 因为训练的过程是通过降低偏差来不断提高最终分类器的精度。 由于上述高偏差和简单的要求,每个分类回归树的深度不会很深。最终的总分类器是将每轮训练得到的弱分类器加权求和得到的(也就是加法模型)。其训练过程如下:
在这里插入图片描述
GBDT无论用于分类还是回归一直都是使用的CART回归树。GBDT 来解决二分类问题和解决回归问题的本质是一样的,都是通过不断构建决策树的方式,使预测结果一步步的接近目标值, 但是二分类问题和回归问题的损失函数是不同的,回归问题中一般使用的是平方损失, 而二分类问题中, GBDT和逻辑回归一样, 使用的如下损失函数:
在这里插入图片描述
在这里插入图片描述

残差就是 yi-pi,GBDT二分类的这个思想,用一系列的梯度提升树去拟合这个对数几率, 其分类模型可以表达为:
在这里插入图片描述
构建分类GBDT的步骤有两个:

  1. 初始化GBDT:分类 GBDT 的初始状态也只有一个叶子节点,该节点为所有样本的初始预测值,如下:
    在这里插入图片描述
    上式里面, F代表GBDT模型, F0是模型的初识状态, 该式子的意思是找到一个γ ,使所有样本的 Loss 最小,在这里及下文中, γ都表示节点的输出,即叶子节点, 且它是一个对数形式的值(回归值),在初始状态γ=F0 。
  2. 循环生成决策树:有4小步, 第一就是计算负梯度值得到残差, 第二步是用回归树拟合残差,第三步是计算叶子节点的输出值, 第四步是更新模型。
    1. 计算负梯度得到残差
      在这里插入图片描述

    2. 使用回归树来拟合残差:遍历每个特征, 每个特征下遍历每个取值, 计算分裂后两组数据的平方损失, 找到最小的那个划分节点。

    3. 对于每个叶子节点 , 计算最佳残差拟合值
      在这里插入图片描述

    4. 更新模型
      在这里插入图片描述

GBDT的优点:
我们可以把树的生成过程理解成自动进行多维度的特征组合的过程,从根结点到叶子节点上的整个路径(多个特征值判断),才能最终决定一棵树的预测值, 另外,对于连续型特征的处理,GBDT 可以拆分出一个临界阈值,比如大于 0.027走左子树,小于等于 0.027(或者 default 值)走右子树,这样很好的规避了人工离散化的问题。这样就非常轻松的解决了逻辑回归那里自动发现特征并进行有效组合的问题, 这也是GBDT的优势所在。

GBDT的缺点:
对于海量的id类特征,GBDT 由于树的深度和棵树限制(防止过拟合),不能有效的存储;另外海量特征在也会存在性能瓶颈,当 GBDT 的 one hot 特征大于 10 万维时,就必须做分布式的训练才能保证不爆内存。所以 GBDT 通常配合少量的反馈 CTR 特征来表达,这样虽然具有一定的范化能力,但是同时会有信息损失对于头部资源不能有效的表达

三、GBDT+LR模型

GBDT+LR模型:用GBDT自动进行特征筛选和组合, 进而生成新的离散特征向量, 再把该特征向量当做LR模型的输入, 来产生最后的预测结果。GBDT+LR 使用最广泛的场景是CTR点击率预估,即预测当给用户推送的广告会不会被用户点击。

在这里插入图片描述
训练时,GBDT 建树的过程相当于自动进行的特征组合和离散化,然后从根结点到叶子节点的这条路径就可以看成是不同特征进行的特征组合,用叶子节点可以唯一的表示这条路径,并作为一个离散特征传入 LR 进行二次训练。

比如上图中, 有两棵树,x为一条输入样本,遍历两棵树后,x样本分别落到两颗树的叶子节点上,每个叶子节点对应LR一维特征,那么通过遍历树,就得到了该样本对应的所有LR特征。构造的新特征向量是取值0/1的。 比如左树有三个叶子节点,右树有两个叶子节点,最终的特征即为五维的向量。对于输入x,假设他落在左树第二个节点,编码[0,1,0],落在右树第二个节点则编码[0,1],所以整体的编码为[0,1,0,0,1],这类编码作为特征,输入到线性分类模型(LR or FM)中进行分类。

预测时,会先走 GBDT 的每棵树,得到某个叶子节点对应的一个离散特征(即一组特征组合),然后把该特征以 one-hot 形式传入 LR 进行线性加权预测。

几个关键的点:

  1. 通过GBDT进行特征组合之后得到的离散向量是和训练数据的原特征一块作为逻辑回归的输入, 而不仅仅全是这种离散特征
  2. 建树的时候用ensemble建树的原因就是一棵树的表达能力很弱,不足以表达多个有区分性的特征组合,多棵树的表达能力更强一些。GBDT每棵树都在学习前面棵树尚存的不足,迭代多少次就会生成多少棵树。
  3. RF也是多棵树,但从效果上有实践证明不如GBDT。且GBDT前面的树,特征分裂主要体现对多数样本有区分度的特征;后面的树,主要体现的是经过前N颗树,残差仍然较大的少数样本。优先选用在整体上有区分度的特征,再选用针对少数样本有区分度的特征,思路更加合理,这应该也是用GBDT的原因。
  4. 在CRT预估中, GBDT一般会建立两类树(非ID特征建一类, ID类特征建一类), AD,ID类特征在CTR预估中是非常重要的特征,直接将AD,ID作为feature进行建树不可行,故考虑为每个AD,ID建GBDT树。
    1. 非ID类树:不以细粒度的ID建树,此类树作为base,即便曝光少的广告、广告主,仍可以通过此类树得到有区分性的特征、特征组合
    2. ID类树:以细粒度 的ID建一类树,用于发现曝光充分的ID对应有区分性的特征、特征组合

四、编程实践

  1. 训练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,
)
  1. 特征转换并构建新的数据集
model = gbm.booster_ # 获取到建立的树
# 每个样本落在每个树的位置 , 下面两个是矩阵 (样本个数, 树的棵树) , 每一个数字代表某个样本落在了某
个数的哪个叶子节点
gbdt_feats_train = model.predict(train, pred_leaf = True)
gbdt_feats_test = model.predict(test, pred_leaf = True)

# 把上面的矩阵转成新的样本-特征的形式, 与原有的数据集合并
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)

# 构造新数据集
train = pd.concat([train, df_train_gbdt_feats], axis = 1)
test = pd.concat([test, df_test_gbdt_feats], axis = 1)
train_len = train.shape[0]
data = pd.concat([train, test])
  1. 离散特征的独热编码,并划分数据集
# 新数据的新特征进行读入编码
for col in gbdt_feats_name:
	onehot_feats = pd.get_dummies(data[col], prefix = col)
	data.drop([col], axis = 1, inplace = True)
	data = pd.concat([data, onehot_feats], axis = 1)
# 划分数据集
train = data[: train_len]
test = data[train_len:]

x_train, x_val, y_train, y_val = train_test_split(train, target, test_size = 0.3, random_state = 2018)
  1. 训练逻辑回归模型作最后的预测
# 训练逻辑回归模型
lr = LogisticRegression()
lr.fit(x_train, y_train)
tr_logloss = log_loss(y_train, lr.predict_proba(x_train)[:, 1])
print('tr-logloss: ', tr_logloss)
val_logloss = log_loss(y_val, lr.predict_proba(x_val)[:, 1])
print('val-logloss: ', val_logloss)

# 预测
y_pred = lr.predict_proba(test)[:, 1]

本博客内容来自datawhale组队学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值