任务8:向量召回基础
- 基于任务7的基础上,使用编码后的用户向量,计算用户相似度。
- 参考User-CF的过程,通过用户相似度得到电影推荐
代码地址: https://github.com/Guadzilla/Basics-of-Recsys
任务 7 中,我们在 Movielens-1m 数据集上用 word2vec 训练得到了 电影的”词向量”(物品向量、item embedding,都是一个意思,下面都用 item embedding),再对用户所有看过的电影的 embedding 取均值作为”句向量“(用户向量,user embedding)。
在任务 7 的 word2vec_rec.py 里,实现了在 Movielens 数据集上用 Word2Vec 对用户进行推荐,主要步骤为:划分数据集、训练word2vec模型、计算用户向量、TopN推荐(计算相似物品)。
任务 8 就以它为基础,稍作修改,主要步骤为:划分数据集、训练word2vec模型、计算用户向量、计算用户相似度、建立向量库、构建用户相似性矩阵、利用UserCF算法进行TopN推荐。因为前三步骤和之前类似,不做过多介绍,这里重点介绍后四步。
计算用户相似度
计算用户相似度的思路是,利用 faiss 库建立向量库,存入所有 user embedding,再用 user embedding 对向量库进行检索,取出 TopK 个最相似的用户,用户后续的 UserCF 推荐。
因为用 faiss 构建向量库会对 userID 重新从0开始索引,取出结果也是根据重新索引后的 index 来取,所以有必要提前对训练集的 userID 重建索引,用一个字典映射来实现。
实际上在 load 数据集的时候已经对 userID 和 itemID 重新索引了,这里为什么还要再做一次索引呢?
答:为了方便索引,使得训练集和验证集可以直接对向量库进行索引。具体来说,划分数据集会造成训练集和验证集上的用户数量不一致,也就是说可能有一部分用户只在验证集出现,训练集里没有他。例如:全部数据集有10个用户,并且已经对他们从零开始编号,userID=[0,1,2,3,4,5,6,7,8,9]
。随机划分数据集以后,训练集里可能就只有userID = [0,2,3,4,5,6,7,8]
这8个用户了,验证集里只有 userID = [0,1,2,3,4,5,6,7,9]
9个用户。此时如果直接把训练集的 user embedding 直接放到索引库里,faiss 为向量库构建的索引为index = [0,1,2,3,4,5,6,7]
,对应关系是index=0对应userID=0
,index=1对应userID=2
,…,这个对应关系必须保存下来,否则验证集只有 userID ,无法定位到 userID 对应哪个索引,也就无法提取该 user embedding。如果用字典 MAP(key=userID,value=index)
保存下来这个对应关系,在训练集上就可以用MAP[userID]
作为索引从向量库提取 user embedding ;验证集上,首先把在验证集首次出现的用户单独保存,剩下userID = [0,2,3,4,5,6,7]
,其余一样。
在这里使用了另一种思路,先对训练集 userID = [0,2,3,4,5,6,7,8]
重新索引成 userID = [0,1,2,3,4,5,6,7]
,并保存下这个字典MAP(key=userID,value=index)
,再把验证集 userID = [0,1,2,3,4,5,6,7,9]
的 userID 都 MAP 到 index 上,其中 1 和 9 在训练集上没有出现,单独保存,剩下的userID = [0,2,3,4,5,6,7]
再做映射,变成 userID = [0,1,2,3,4,5,6]
,这样做方便在以后就可以直接用 userID 访问向量库。
两种方式都可以,第一种方式的缺点是频繁访问字典,但优点是不用 in place 修改数据;第二种方式正好相反,不用频繁访问字典,但是需要 in place 修改数据。个人习惯用第二种方式,一劳永逸。
下面是代码部分:
1 | TopK = 100 |
建立向量索引库
要用 faiss 计算余弦相似度,需要注意的是 faiss 自带的两种常见相似算法是:faiss.IndexFlatL2()
用来计算向量距离,和faiss.IndexFlatIP()
用来计算向量内积。计算余弦相似度可以用向量内积形式,但前提是需要先把向量转成单位向量,faiss 自带了 faiss.normalize_L2()
就是用来单位化向量的。
1 | # 建立用户向量索引库 |
构建用户相似性矩阵
构建用户相似性的思路是用字典保存,因为矩阵太稀疏,浪费空间。
1 | # 找TopK相似用户 |
利用 UserCF 算法进行 TopN 推荐
UserCF 的思路,先找到和目标用户最相似的 TopK 个用户(相似度用于计算目标用户对陌生物品的得分)再计算这些用户看过的、且目标用户没看过的电影的得分,对有得分的物品进行排序,进行 TopN 推荐。
1 | # 推荐TopN相似商品 |
最后进行评估,验证集上实验结果:
1 | # evaluate |
完整代码见 recpre/task8 at master · Guadzilla/recpre (github.com)