本文是对七月在线推荐课程第二课中的一个课堂笔记记录。 本课笔记主要围绕从搜索与推荐是什么与两者的区别联系,以及介绍了SVD 和SVD++的公式原理与代码实现。
召回是一个拉取候选集的过程,往往就是一个匹配的问题,而且很多匹配特征会是排序阶段的重要依据。搜索、推荐、广告本身其实就是一个匹配问题。
搜索与推荐的 overview
搜索的匹配
Search Engine
推荐系统的架构:
Matching 阶段: 追求的主要是性能,
ranking阶段: 要的是精度
Query Document Mismatch :语义歧义性问题
词汇不同但是语义相同
词汇相似但是语义相同 (这个问题不大)
词汇不同但是语义却相似
推荐引擎面临的问题: user-item 存在的语义gap (这个待细查,这只是个简述)
搜索与推荐的联系与区别:
⊚ Common goal: matching a context (may or may not include an explicit query) to a collection of information objects (product descriptions, web pages, etc.)
⊚ Difference for search and recommendation: features used for matching!
Semantic Gap
query-document mismatch
◦ Same intent can be represented by different queries (representations) ..(sematic matching)
◦ Search is still mainly based on term level matching基于词汇匹配仍然主要的基模型
⊚ User-item Semantic Gap
简单的term level的表达匹配
Matching in term space :
TF-IDF: 理解与计算公式
BM25 模型: 简单了解。
Matching in Latent Space 隐式空间的匹配
original space
latent space
⊚ Queries and documents have similarities
⊚ Project queries and documents to latent space
⊚ The goal is to make similar items distance to be smaller
缩小语义距离的部分方式:
语义向量空间映射
高维语义维度降维 :
协同过滤:
概念:
类别:
user-based CF
item-Based CF
model-based CF : svd ,svd++ ,svm
SVD: singular value decomposition
用于cf的svd :
矩阵分解:
svd 分解的缺陷不足:
SVD
The equation is:
𝜇 : 训练集中所有记录的评分的全局平均数。在不同网站中,因为网站定位和销售的物品不同,网站的整体评分分布也会显示出一些差异。比如有些网站中的用户就是喜欢打高分,而另一些网站的用户就是喜欢打低分。而全局平均数可以表示网站本身对用户评分的影响
𝑏𝑢: 用户偏置(user bias)项。这一项表示了用户的评分习惯中和物品没有关系的那种因素。比如有些用户就是比较苛刻,对什么东西要求都很高,那么他的评分就会偏低,而有些用户比较宽容,对什么东西都觉得不错,那么他的评分就会偏高。
𝑏𝑖: 物品偏置(item bias)项。这一项表示了物品接受的评分中和用户没有什么关系的因素。比如有些物品本身质量就很高,因此获得的评分相对都比较高,而有些物品本身质量很差,因此获得的评分相对都会比较低。
$q_i$ 的含义是指 : item的向量
$p_u$ 的含义是指 user的向量
损失函数:
import numpy as np
class SVD:
# What is mean?
def __init__(self, learning_rate, regularized_rate, max_step, n_users, n_items, n_factors):
# learning_rate对应上面的gamma学习率参数,regularized_rate对应上面的lambda ,max_step训练的步数,n_facotors值的是user和item的向量空间维度
self.learning_rate = learning_rate
self.regularized_rate = regularized_rate
self.max_step = max_step
self.bu = np.zeros(n_users, np.double)
self.bi = np.zeros(n_items, np.double)
self.pu = np.zeros((n_users, n_factors), np.double) #
self.qi = np.zeros((n_items, n_factors), np.double)
self.mean = 0
def get_pred_value(u, i):
return self.mean + self.bu[u] + self.bi[i] + np.dot(self.pu[u], self.qi[i])
# There is a problem here, can anyone find it?
def fit(self, X, y): #拟合的过程
for index, row in X.iterrows():
u, i, r = row['user_id'], row['item_id'], row['rating']
error = r - self.get_pred_value(u, i) # 原值减去拟合值
self.bu[u] += self.learning_rate * (err - self.regularized_rate * self.bu[u])
self.bi[i] += self.learning_rate * (err - self.regularized_rate * self.bi[i])
tmp = self.pu[u] #加中间变量,减少后面的q[i]更新穿越
self.pu[u] += self.learning_rate * (err * self.qi[i] - self.regularized_rate * self.pu[u])
self.qi[i] += self.learning_rate * (err * tmp - self.regularized_rate * self.qi[i])
if index == self.max_step:
break
return self
# What if the one to predict is not inside our knowledge? -- 当item如果不在历史数据中,则可以直接报错或者将整体平均值返回,这是由于svd++算法的限制。
def transform(self, X):
result = [0] * len(X)
for index, row in X.iterrows():
u, i, r = row['user_id'], row['item_id'], row['rating']
result[index] = self.get_pred_value(u, i)
return result
SVD++
某个用户对某个电影进行了评分,那么说明他看过这部电影,那么这样的行为事实上蕴含了一定的信息,因此我们可以这样来理解问题:评分的行为从侧面反映了用户的喜好,可以将这样的反映通过隐式参数的形式体现在模型中,从而得到一个更为精细的模型,便是 SVD++. 在SVD函数中,在预测用户u对电影(或商品)i的评分时,只考虑了用户特征向量和电影(商品)特征向量,以及评分相对于平均分的偏置向量。 在SVD++中,更进一步考虑了用户对其所有有过评分行为的商品的隐式反馈。预测函数变为:
SVD++公示相比与SVD ,最后面的由原来的𝑝𝑢pu 变成了
这一项是从隐式反馈的角度出发的. 其中里面的参数|𝐼𝑢||Iu|是当前用户所有打过分的item集合的长度((对于商品推荐场景也可以是浏览和评分过的商品的集合的长度) ,yj为隐藏的“评价了电影 j”反映出的个人喜好偏置,收缩因子取集合大小的根号是一个经验公式,并没有理论依据。
鸣谢与参考:
七月在线https://www.julyedu.com/video/play/370/10802
https://www.bbsmax.com/A/QV5ZQw8nJy/
https://cloud.tencent.com/developer/article/1107364