协同过滤仅仅使用有限的用户行为信息,逻辑回归算法模型大多引入用户行为、用户特征、物品特征和上下文特征等,从CF逐步过渡到综合不同特征的机器学习模型。
(1)逻辑回归模型
将用户特征(年龄、性别等)、用户行为(收藏、浏览等)、物品特征(属性、描述等)和上下文特征(当前时间、地点等)转化成数值型特征向量;以点击率为优化目标;利用已有数据进行训练学习模型参数;利用学习完成的模型进行推理预测用户点击率。
(2)POLY2模型--特征交叉的开始
防止“辛普森悖论”(数据在分组研究与总体研究时产生的结论可能是相悖的),改造逻辑回归模型,使其具备特征交叉能力。但是人工难以设计最优特征组合,POLY2采用暴力组合方式。
但是无差别的特征交叉使得原本稀疏的特征变得更加稀疏,权重参数量级也由 n 上升到
(3)FM模型 -- 隐向量特征交叉
将交叉特征权重换成隐向量内积形式,减少参数稀疏性和计算复杂度
(4) FFM模型 -- 引入特征域的概念
FFF在模型训练过程中,需要学习 n 个特征在 f 个域上的 k 维隐向量,使每个特征在与不同域的特征交叉时采用不同的隐向量
(5) GBDT+LR -- 特征工程模型化的开端
LR模型将推荐问题转换为CTR预测分类问题,但是特征工程构建复杂,特征交叉方式也仅能做到二阶(提高交叉维度会产生组合爆炸问题);GBDT进行特征筛选与组合,生成新的离散特征向量;将生成特征(concatenate到原始特征)作为LR模型输入特征。
- 引入GBDT,但是树模型不适应高维离散特征
- 树模型的正则项一般为深度和叶子节点数
- LR模型对参数W进行正则化,约束了w不可能过大,即不会聚焦个别特征
- 针对高位离散特征,树模型很有可能根据训练集某些个别特征巧合的实现数据划分
代码复现:(大多参考附录2实现,感谢)
数据下载链接:
criteo数据用于推荐系统学习-深度学习文档类资源-CSDN文库https://download.csdn.net/download/Big_Huang/85155340
import lightgbm as lgb
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
df_data = pd.read_csv('./criteo/train.csv', sep=',')
df_data.drop(['Id'], axis=1, inplace=True)
df_data.fillna(-1, inplace=True)
continuous_fea = ['I'+str(i+1) for i in range(13)]
category_fea = ['C'+str(i+1) for i in range(26)]
# 离散特征one-hot编码
for col in category_fea:
onehot_feats = pd.get_dummies(df_data[col], prefix=col)
df_data.drop([col], axis=1, inplace=True)
df_data = pd.concat([df_data, onehot_feats], axis=1)
label = df_data.pop('Label')
# 划分数据集
x_train, x_val, y_train, y_val = train_test_split(df_data, label, test_size=0.2, random_state=28)
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_ # 获取到建立的树
# 每个样本落在每个树的位置 , 下面两个是矩阵 (样本个数, 树的棵树) , 每一个数字代表某个样本落在了某个数的哪个叶子节点
gbdt_feats_train = model.predict(df_data, 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)
# 构造新数据集
train = pd.concat([df_data, df_train_gbdt_feats], axis = 1)
from sklearn.preprocessing import MinMaxScaler
# 连续特征归一化
scaler = MinMaxScaler()
for col in continuous_fea:
train[col] = scaler.fit_transform(train[col].values.reshape(-1, 1))
# 新数据的新特征进行读入编码
for col in gbdt_feats_name:
onehot_feats = pd.get_dummies(train[col], prefix = col)
train.drop([col], axis = 1, inplace = True)
train = pd.concat([train, onehot_feats], axis = 1)
x_train, x_val, y_train, y_val = train_test_split(train, label, test_size = 0.3, random_state = 28)
# 训练逻辑回归模型
lr = LogisticRegression()
lr.fit(x_train, y_train)
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
from sklearn.metrics import roc_auc_score
def eval_model(y_pred, y_true):
print(f"accuracy_score = {accuracy_score(y_true, y_pred)}")
print(f"precision_score = {precision_score(y_true, y_pred)}")
print(f"recall_score = {recall_score(y_true, y_pred)}")
print(f"f1_score = {f1_score(y_true, y_pred)}")
print(f"auc = {roc_auc_score(y_true, y_pred)}")
pred = [1 if x >= 0.5 else 0 for x in lr.predict_proba(x_val)[:, 1]]
eval_model(pred, np.array(y_val))
参考:
1. 《深度学习推荐系统》