第一种结果——逻辑

先来回顾一下上一篇文章,文章中我们获得了三个特征:

  1. 用户特征
  2. 广告特征
  3. 用户和广告的关系表

我们使用CountVectorizer,OneHotEncoder,LabelEncoder,将所有特征压成一个 list,然后使用 lightGBM 模型来训练

1
2
3
4
5
6
7
8
9
10
import lightgbm as lgb
clf = lgb.LGBMClassifier(
boosting_type='gbdt', num_leaves=31, reg_alpha=0.0, reg_lambda=1,
max_depth=-1, n_estimators=1500, objective='binary',
subsample=0.7, colsample_bytree=0.7, subsample_freq=1,
learning_rate=0.05, min_child_weight=50, random_state=2018, n_jobs=-1
)
clf.fit(train_x, train_y, eval_set=[(train_x, train_y)], eval_metric='auc',early_stopping_rounds=100)

label = clf.predict(test_x)

最后得到的 label 是一个包含-1或1的 list。在生产环境中我们会不断的扫描新用户和新广告的特征,提取后用这个模型预测,把结果中为1的广告(aid)保存下来,最后投放给对应的用户(uid)。这是机器学习中一般的结果。

第二种结果——线性

在参考资料 elasticsearch-spark-recommender 中,作者介绍了如何用 elasticsearch 和 spark 来做协同过滤推荐系统。例子有两个特征:

  1. 电影特征(年份、类型)
  2. 用户对电影的打分

例子中用 spark 提供的最小二乘机来训练模型,然后把得到的特征数组合并成字符串保存到 elasticsearch 中(文章里介绍了把spark 读写 es 的插件)

1
2
3
4
5
from pyspark.ml.recommendation import ALS
from pyspark.sql.functions import col
# 训练
als = ALS(userCol="userId", itemCol="movieId", ratingCol="rating", regParam=0.01, rank=20, seed=12)
model = als.fit(ratings_from_es)

每个电影的 document 中会多一行

1
vector: '1.0348|2.329487|8.3456435|5.293874'

当用户打开一个电影的网页,系统得到这部电影的特征 vector,然后输入 elasticsearch 进行搜索,es 会以’|’分隔字符串,然后无序匹配,得到匹配数字(其实是字符串)最多的电影返回给用户。这样一个协同过滤推荐系统就完成了。

控制结果精度,得到邻近推荐

上面的例子,结果是很多浮点数的组合,但是一些算法得出的结果是一个浮点数。假设你根据用户的特征,得到的结果是0.123456789,而你需要给用户推荐相似的结果,那么应该减少结果的位数,比如取0.12345,然后匹配所有前6为相同的结果。取多少位应该根据具体数据量来。比如精确到6位得到的推荐结果挺多,但精确到7位就非常少了,那么取6位就比较合适。


参考资料:
Machine-Learning:https://github.com/Jack-Cherish/Machine-Learning
elasticsearch-spark-recommender:https://github.com/IBM/elasticsearch-spark-recommender