协同过滤算法 “协同大家的反馈、评价和意见一起对海量的信息进行过滤,从中筛选出用户可能感兴趣的信息”。
首先,我们可以看到,电商网站的商品库里一共有 4 件商品:一个游戏机、一本小说、一本杂志,以及一台电视机。假设,现在有一名用户 X访问了这个电商网站,电商网站的推荐系统需要决定是否推荐电视机给用户 X。
为了进行这项预测,推荐系统可以利用的数据有用户 X 对其他商品的历史评价数据,以及其他用户对这些商品的历史评价数据。我在图 1(b)中用绿色“点赞”的标志表示好评,用红色“踩”的标志表示了差评。这样一来,用户、商品和评价记录就构成了带有标识的有向图。
接下来,为了方便计算,我们将有向图转换成矩阵的形式。这个矩阵表示了物品共同出现的情况,因此被称为“共现矩阵”。其中,用户作为矩阵行坐标,物品作为列坐标,我们再把“点赞”和“踩”的用户行为数据转换为矩阵中相应的元素值。这里,我们将“点赞”的值设为 1,将“踩”的值设为 -1,“没有数据”置为 0(如果用户对物品有具体的评分,那么共现矩阵中的元素值可以取具体的评分值,没有数据时的默认评分也可以取评分的均值)。
你发现了吗,生成共现矩阵之后,推荐问题就转换成了预测矩阵中问号元素(图1(d) 所示)的值的问题。由于在“协同”过滤算法中,推荐的原理是让用户考虑与自己兴趣相似用户的意见。因此,我们预测的第一步就是找到与用户X 兴趣最相似的 n(Top n 用户,这里的 n 是一个超参数)个用户,然后综合相似用户对“电视机”的评价,得出用户 X 对“电视机”评价的预测。
从共现矩阵中我们可以知道,用户 B 和用户 C 由于跟用户 X 的行向量近似,被选为 Top n(这里假设 n 取 2)相似用户,接着在图 1(e) 中我们可以看到,用户 B 和用户 C 对“电视机”的评价均是负面的。因为相似用户对“电视机”的评价是负面的,所以我们可以预测出用户 X 对“电视机”的评价也是负面的。在实际的推荐过程中,推荐系统不会向用户 X推荐“电视机”这一物品。
到这里,协同过滤的算法流程我们就说完了。也许你也已经发现了,这个过程中有两点不严谨的地方,一是用户相似度到底该怎么定义,二是最后我们预测用户 X 对“电视机”的评价也是负面的,这个负面程度应该有一个分数来衡量,但这个推荐分数该怎么计算呢?
用户评分的预测
在获得 Top n 个相似用户之后,利用 Top n 用户生成最终的用户 u 对物品 p 的评分是一个比较直接的过程。 利用用户相似度和相似用户评价的加权平均值,来获得目标用户的评价预测,公式如下所示。
Ru,p= ∑sϵS(wu,s⋅Rs,p)/ ∑s∈Swu,s
其中,权重 wu,s 是用户 u 和用户 s 的相似度,Rs,p 是用户 s 对物品 p 的评分。
矩阵分解算法的原理
矩阵分解的主要过程,就是先分解协同过滤生成的共现矩阵,生成用户和物品的隐向量,再通过用户和物品隐向量间的相似性进行推荐。
那这个过程的关键就在于如何分解这个共现矩阵了。从形式上看,矩阵分解的过程是直观的,就是把一个 mxn 的共现矩阵,分解成一个 mxk 的用户矩阵和 kxn 的物品矩阵相乘的形式
损失函数:
rui 是共现矩阵里面用户 u 对物品 i 的评分,qi 是物品向量,pu 是用户向量。通过目标函数的定义我们可以看到,我们要求的物品向量和用户向量,是希望让物品向量和用户向量之积跟原始的评分之差的平方尽量小
矩阵分解算法的 Spark 实现
就是在模型中,我们需要在模型中指定训练样本中用户 ID 对应的列 userIdInt 和物品 ID 对应的列 movieIdInt,并且两个 ID 列对应的数据类型需要是 int 类型的。
// 建立矩阵分解模型
val als = new ALS()
.setMaxIter(5)
.setRegParam(0.01)
.setUserCol("userIdInt")
.setItemCol("movieIdInt")
.setRatingCol("ratingFloat")
//训练模型
val model = als.fit(training)
//得到物品向量和用户向量
model.itemFactors.show(10, truncate = false)
model.userFactors.show(10, truncate = false
- 基于协同过滤算法,你能找到进行相似“物品”推荐的方法吗?
取topn个相似物品 从 u2i,i2i,或者u2u2i等里计算出
- 在 MovieLens 数据集中,不同用户对物品打分的标准不尽相同。比如说,有的人可能爱打高分,评价的影片得分都在 4 分以上,有的人爱打低分,大部分影片都在 3 分以下。你觉得这样的偏好对于推荐结果有影响吗?我们能不能在算法中消除这种偏好呢?
经典的做法是在生成共现矩阵的时候对用户的评分进行用户级别的校正或者归一化,用当前得分减去用户平均得分作为共现矩阵里面的值。