1. 简介
1.1 定义
没有明确需求的用户访问了我们的服务, 且服务的物品对用户构成了信息过载, 系统通过一定的规则对物品进行排序,并将排在前面的物品展示给用户,这样的系统就是推荐系统
信息过载 & 用户需求不明确
分类目录
搜索引擎
推荐系统
推荐系统 V.S. 搜索引擎
行为方式
意图
个性化
流量分布
目标
-
推荐系统的工作原理及作用
- 社会化推荐 基于内容的推荐 基于流行度的推荐 基于协同过滤的推荐
- 推荐系统的作用
- 高效连接用户和物品
- 提高用户停留时间和用户活跃程度
- 有效的帮助产品实现其商业价值
-
推荐系统和Web项目的区别
通过信息过滤实现目标提升 V.S. 稳定的信息流通系统
不确定思维 V.S. 确定
1.2 架构设计
1. 推荐系统要素
- UI 和 UE(前端界面)
- 数据 (Lambda架构)
- 业务知识
- 算法
2. 推荐系统架构
- 推荐系统整体架构
- Lambda架构
推荐算法架构
召回阶段 (海选)
排序阶段(精选)根据用户特征物品的特征,构造排序模型,对预测样本进行评估,计算出点击率,根据点击率进行排序
策略调整
1.3 推荐算法
1. 推荐模型构建流程
Data(数据)->Features(特征)->ML Algorithm(选择算法训练模型)->Prediction Output(预测输出)
2. 最经典的推荐算法:协同过滤推荐算法
算法思想:物以类聚,人以群分
基本的协同过滤推荐算法基于以下假设:
- “跟你喜好相似的人喜欢的东西你也很有可能喜欢” :基于用户的协同过滤推荐(User-based CF)
- “跟你喜欢的东西相似的东西你也很有可能喜欢 ”:基于物品的协同过滤推荐(Item-based CF)
找出最相似的人或物品:TOP-N相似的人或物品
根据相似的人或物品产生推荐结果
3. 相似度计算
欧氏距离,
余弦相似度
皮尔逊相关系数Pearson
杰卡德相似度 Jaccard
- 两个集合的交集元素个数在并集中所占的比例, 非常适用于布尔向量表示
如何选择相似度计算方法:
- 余弦相似度/皮尔逊相关系数适合用户评分数据(实数值),
- 杰卡德相似度适用于隐式反馈数据(0,1布尔值 是否收藏,是否点击,是否加购物车)
4. 协同过滤推荐算法代码实现
构建数据集
用1、0分别来表示用户的是否购买过该物品,数据集如下所示:
接下来进行相似度的计算,由于是0,1这样的布尔值,所以使用杰卡德相似度:
from sklearn.metrics import jaccard_similarity_score
# 直接计算某两项的杰卡德相似系数
# 计算Item A 和Item B的相似度
print(jaccard_similarity_score(df["Item A"], df["Item B"]))
# 计算所有的数据两两的杰卡德相似系数
from sklearn.metrics.pairwise import pairwise_distances
# 计算用户间相似度
user_similar = 1 - pairwise_distances(df.values, metric="jaccard")
遍历每一行数据 根据相似的人或者物品进行推荐
5. 使用协同过滤推荐算法对用户进行评分预测
构建数据集
计算相似度,皮尔逊相关系数
df.corr()
评分预测:
User-Based CF 评分预测:使用用户间的相似度进行预测
Item-Based CF 评分预测:使用物品间的相似度进行预测
User-Based CF与Item-Based CF比较
- User-Based CF和Item-Based CF 严格意义上属于两种不同的推荐算法(预测评分结果存在差异)
- User-Based CF应用场景:用户少于物品,或者用户没用物品变化快的场景 (举例,信息流产品)
- Item-Based CF应用场景:用户多于物品,或者物品变化较慢的场景 (举例,电商应用)
- 不好确定那种更合适,可以两种算法都去实现,然后对推荐效果进行评估分析选出更优方案
1.4 案例–基于协同过滤的电影推荐
1. User-Based CF 预测电影评分
数据集下载,包含了对9742部电影的100836次评分和3683个标签;
加载ratings.csv,转换为用户-电影评分矩阵并计算用户之间相似度
ratings_matrix = ratings.pivot_table(index=["userId"], columns=["movieId"],values="rating")
预测用户对物品的评分 (以用户1对电影1评分为例)
1. 找出uid用户的相似用户
相似用户筛选规则:正相关的用户
2. 从用户1的近邻相似用户中筛选出对物品1有评分记录的近邻用户
3. 结合uid用户与其近邻用户的相似度预测uid用户对iid物品的评分
4 计算预测的评分值
封装成方法 预测任意用户对任意电影的评分 predict
为某一用户预测所有电影评分
根据评分为指定用户推荐topN个电影
2. Item-Based CF 预测电影评分
加载ratings.csv,转换为用户-电影评分矩阵并计算用户之间相似度
预测用户对物品的评分 (以用户1对电影1评分为例)
1. 找出iid物品的相似物品
相似物品筛选规则:正相关的物品
2. 从iid物品的近邻相似物品中筛选出uid用户评分过的物品
3. 结合iid物品与其相似物品的相似度和uid用户对其相似物品的评分,预测uid对iid的评分
计算预测的评分值并返回
1.5 推荐系统评估
1. 评估指标
-
好的推荐系统可以实现用户, 服务提供方, 内容提供方的共赢
-
评估数据来源显示反馈和隐式反馈
- 显式反馈 准确性高 数量少 成本高
- 隐式反馈 相反
-
常用评估指标
• 准确性 • 信任度
• 满意度 • 实时性
• 覆盖率 • 鲁棒性
• 多样性 • 可扩展性
• 新颖性 • 商业⽬标
• 惊喜度 • ⽤户留存
2. 评估方法
- 问卷调查: 成本高
- 离线评估
- 在线评估: 灰度发布 & A/B测试
- 实践: 离线评估和在线评估结合, 定期做问卷调查
3. 冷启动问题
- 用户冷启动:如何为新用户做个性化推荐
- 物品冷启动:如何将新物品推荐给⽤户
- 系统冷启动:用户冷启动+物品冷启动
用户冷启动:尽可能收集用户特征数据
- 1 收集用户的基本信息
- 2 引导用户填写兴趣
- 3 使用其它站点/应用的行为数据, 例如腾讯视频&QQ音乐
- 4 新老用户推荐策略的差异
物品冷启动
- 给物品打标签
- 利用物品的内容信息,将新物品先投放给曾经喜欢过和它内容相似的其他物品的用户。
系统冷启动
- 基于内容的推荐 系统早期
- 基于内容的推荐逐渐过渡到协同过滤
- 基于内容的推荐会一直存在,综合考虑基于内容推荐和协同过滤的结果
2. 算法
2.1 基于模型的协同过滤算法
协同过滤算法的两大类别简介
Memory-Based CF 一般可以用在稠密矩阵
- 利用用户行为数据(点击,购买,评分)计算相似度(余弦,皮尔逊,杰卡德)
Model-Based CF 用在稀疏矩阵
-
利用机器学习算法预测用户对物品的喜好程度
-
基于回归模型的协同过滤推荐
-
基于矩阵分解的协同过滤推荐
2. 基于回归模型的协同过滤推荐
2.1 Baseline:基准原理
将评分看作是一个连续的值而不是离散的值,那么就可以借助线性回归思想来预测目标用户对某物品的评分。
Baseline设计思想基于以下的假设:
- 有些用户的评分普遍高于其他用户,有些用户的评分普遍低于其他用户。比如有些用户天生愿意给别人好评,心慈手软,比较好说话,而有的人就比较苛刻,总是评分不超过3分(5分满分)
- 一些物品的评分普遍高于其他物品,一些物品的评分普遍低于其他物品。比如一些物品一被生产便决定了它的地位,有的比较受人们欢迎,有的则被人嫌弃。
Baseline目标:
- 找出每个用户普遍高于或低于他人的偏置值bu
- 找出每件物品普遍高于或低于其他物品的偏置值b**i
- 我们的目标也就转化为寻找最优的bu和bi
- 预测用户对电影的评分
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4DAKck4x-1608288760651)(…/day15.assets/image-20201218091845832.png)]
构建损失函数
对于最小过程的求解,我们一般采用随机梯度下降法或者交替最小二乘法来优化实现。
2.2 Baseline的随机梯度下降法优化
梯度下降法推导
损失函数
更新公式
bu bi更新的表达式
算法实现
数据加载
数据初始化
- 初始化一个dict bu,元素个数=用户数量
- 初始化一个dict bi,元素个数=电影数量
更新bu bi
- 初始的bu 和 bi 均为0 ,每一次迭代都会更新一次bu bi
- 根据梯度下降的原理,只要学习率选择的合适,每更新一次bu,bi,预测的损失就会降低一些,直至找到损失函数的极值点
预测评分
predict_rating = global_mean + bu[uid] + bi[iid]
3 准确性指标评估
- 训练集测试集划分,保证每个用户的评分数据在训练集和测试集中都存在,所以定义data_split
- 创建accuary方法计算准确性指标,计算rmse mae
- 添加test方法, 利用训练集评估训练结果
- 整体封装
4 交替最小二乘法优化
最小二乘法思想:对损失函数求偏导,然后再使偏导为0
可以得到bu bi的表达式
bu表达式中含有bi,bi表达式中含有bu
计算bu时把bi当作已知值,计算bi时把bu当作已知值,反复交替进行计算
交替最小二乘法
- 数据加载初始化与之前完全相同
- 迭代更新bu bi
整体封装
3 基于矩阵分解的协同过滤算法
1 矩阵分解发展史
Traditional SVD:
- 通常SVD矩阵分解指的是SVD(奇异值)分解技术
- Traditional SVD分解的形式为3个矩阵相乘,中间矩阵为奇异值矩阵。
- SVD分解的前提:矩阵是稠密的
FunkSVD(LFM, latent factor model)
- Funk SVD不再将矩阵分解为3个矩阵,而是分解为2个矩阵(用户-隐含特征矩阵,物品-隐含特征矩阵)
- Funk SVD也被称为最原始的LFM模型
BiasSVD:
- 在FunkSVD提出后,出现了很多变形版本,其中一个相对成功的方法是BiasSVD,即带有偏置项的SVD
SVD++:
- SVD++:改进的BiasSVD,该算法是在BiasSVD的基础上添加了用户的隐式反馈信息:
2 LFM原理解析
经过处理可以得到原始的用户对于物品的稀疏评分矩阵
使用FunkSVD对这个矩阵进行分解,可以得到两个稠密的小矩阵
用户-隐含特征矩阵,物品-隐含特征矩阵,即可以得到每个用户对于隐含特征的向量,每个物品对于隐含特征的向量
可以使用用户向量和物品向量进行计算,可以得到原始矩阵中确实部分的预测值
步骤:
初始化两个小矩阵,
即可计算预测值(此时肯定是不准的)
构造损失函数,即真实结果和预测结果差值,再加上正则化
可以用梯度下降算法/交替最小二乘法进行优化求解
损失函数
分别求对puk qik的偏导数
使用梯度下降算法,带入到更新公式中
算法实现
- 数据加载
数据初始化
分别初始化两个矩阵,代表用户隐含特征矩阵,物品隐含特征矩阵,隐含特征数量是超参数
# User-LF 10 代表 隐含因子个数是10个
P = dict(zip(users_ratings.index,np.random.rand(len(users_ratings),10).astype(np.float32)
))
# Item-LF
Q = dict(zip(items_ratings.index,np.random.rand(len(items_ratings),10).astype(np.float32)
))
梯度下降优化损失函数
外循环设置训练次数
内循环是每次取一行dataset数据,分别对对应的uid和iid的向量进行更新
预测
def predict(uid, iid):
return np.dot(P[uid], Q[iid])
4 基于矩阵分解的CF算法实现(二):BiasSvd
1 BiasSvd简介
BiasSvd其实就是前面提到的Funk SVD矩阵分解基础上加上了偏置项。
损失函数
随机梯度下降法优化
5 基于内容的推荐算法
1.基于内容的推荐实现步骤
画像构建。顾名思义,画像就是刻画物品或用户的特征。本质上就是给用户或物品贴标签。
物品画像
用户画像
- PGC 系统生成
- 物品自带的属性
- 服务提供方设定的属性
- UGC 用户产生
- 用户在享受服务过程中提供的物品的属性
基于内容推荐的算法流程(有用户行为数据):
- 根据物品画像标签构建标签->物品倒排索引
没有用户行为数据如何做基于内容推荐(解决冷启动问题):
- 利用物品画像计算物品间两两相似情况
- 为每个物品产生TOP-N最相似的物品进行相关推荐