推荐系统简介
1. 推荐系统架构
推荐系统的工作原理分类:
- 社会化推荐
- 基于内容的推荐
- 基于流行度的推荐
- 基于协同过滤的推荐
推荐系统架构:
- 前端界面
- 数据(Lambda架构)
- 业务知识
- 算法
大数据Lambda架构:Lamba系统架构提供了一个结合实时数据和Hadoop预先计算的数据环境的混合平台,提供了一个实时数据视图。
分层架构:
- 批处理层:
- 数据不可变,可进行任何计算,可水平扩展
- 高延迟
- 日志收集 Flume
- 分布式存储 Hadoop
- 分布式计算 Hadoop , MapReduce & Spark
- 视图存储数据库 NoSQL , Redis , MySQL
- 实时处理层:
- 流式处理,持续计算
- 存储和分析某个窗口期的数据
- 最终正确性(Eventual accuracy)
- 实时数据收集(消息中间件) flume & kafka
- 实时数据分析(实时计算框架) spark streaming / storm / flink
- 服务层:
- 支持随机读
- 需要在非常短的时间返回结果
- 读取批处理层和实时处理层结果并对其归并
推荐算法架构:
- 召回阶段(海选):召回决定了最终推荐结果的天花板。(注意不要和召回率混为一谈)
常用算法:
- 协同过滤:基于用户、基于物品
- 基于内容:根据用户行为总结出自己的偏好,根据偏好通过文本挖掘技术找到内容上相似的商品。
- 基于隐语义
- 排序阶段:召回决定了最终推荐结果的天花板,排序逼近这个极限,决定了最终的推荐结果。
- CTR预估(点击率预估,使用LR(Linear Regression)算法):估计用户是否会点击某个商品,需要用户的点击数据。
- 策略调整:
2. 推荐算法
2.1 推荐模型构建流程
Data(数据) -> Feature(特征) -> ML Algorithm(机器学习算法) -> Prediction Output(预测输出)
- 数据收集
- 显性数据:
- Rating 打分
- Comments 评论/评价
- 隐性数据:
- Order history 历史订单
- Cart events 加购物车
- Page views 页面浏览
- Click-thru 点击
- Search log 搜索记录
- 显性数据:
- 特征工程
- 协同过滤:user-item 矩阵
- 基于内容:分词tf-idf , word2vec
- 协同过滤:user-item 矩阵
- 训练模型
- 协同过滤:KNN ,矩阵分解
- 评估,模型上线
2.2 基于协同过滤(Collaborative Filtering)的推荐算法
2.2.1 算法思想
物以类聚,人以群分。
2.2.2 基于协同过滤的推荐算法基于以下假设:
(1)“跟你喜好相似的人喜欢的东西你也可能喜欢”:基于用户的协同过滤推荐(User-Based CF);
(2)“跟你喜欢的物品相似的物品你也可能喜欢”:基于物品的协同过滤推荐(Item-Based CF)。
2.2.3 实现协同过滤推荐有以下几个步骤:
(1)找出最相似的人或物品:通过计算两两之间的相似度来进行排序,找出Top-N相似的人或物品。
(2)根据相似的人或物品产生推荐结果
2.2.4 相似度计算(Similarity Calculation)
数据分类:
- 实数值(物品评分情况)
- 布尔值(用户的行为:比如是否点击、是否收藏)
欧氏距离:空间中p, q两个点的距离用欧氏距离可以表示为: E ( p , q ) = ∑ i = 1 n ( p i − q i ) 2 E(p,q) = \sqrt{\sum\limits^n_{i=1} (p_i - q_i)^2} E(p,q)=i=1∑n(pi−qi)2
欧氏距离的值是一个非负数,最大值为正无穷,通常相似度的计算结果希望是[-1,1]或[0,1]之间,一般可以使用如下转换公式:(距离越远,相似度越小)
1 1 + E ( p , q ) \frac{1}{1+E(p,q)} 1+E(p,q)1
(1)余弦相似度
s i m i l a r i t y = c o s ( θ ) = x ⋅ y ∣ ∣ x ∣ ∣ ∣ ∣ y ∣ ∣ = ∑ i = 1 n x i × y i ∑ i = 1 n ( x i ) 2 × ∑ i = 1 n ( y i ) 2 similarity = cos(\theta) = \frac{ \pmb{x} \cdot \pmb{y}}{||\pmb{x}|| ||\pmb{y}||} = \frac{\sum\limits^n_{i=1} \pmb{x}_i \times \pmb{y}_i}{\sqrt{\sum\limits^n_{i=1}(\pmb{x}_i)^2} \times \sqrt{\sum\limits^n_{i=1}(\pmb{y}_i)^2}} similarity=cos(θ)=∣∣xx∣∣∣∣yy∣∣xx⋅yy=i=1∑n(xxi)2×i=1∑n(yyi)2i=1∑nxxi×yyi
- 余弦相似度度量的是两个向量之间的夹角,用夹角的余弦值来度量相似的情况,计算时要先对向量长度进行归一化。
- 余弦相似度在度量文本相似度、用户相似度、物品相似度的时候最为常用。
- 特点:与向量长度无关,即两个向量只要方向一致,无论程度强弱,都可以视为“相似”。
(2)皮尔逊相关系数 Pearson
- 实际上也是一种余弦相似度,只不过先对向量做了中心化,向量 a , b 先减去向量的均值后,再计算余弦相似度。即:
s i m i l a r i t y = c o r r ( x , y ) = ∑ i = 1 n ( x i − x ‾ ) × ( y i − y ‾ ) ∑ i = 1 n ( x i − x ‾ ) 2 × ∑ i = 1 n ( y i − y ‾ ) 2 similarity = corr(\pmb{x}, \pmb{y}) = \frac{\sum\limits^n_{i=1} (\pmb{x}_i - \overline{\pmb{x}}) \times (\pmb{y}_i- \overline{\pmb{y}})}{\sqrt{\sum\limits^n_{i=1}(\pmb{x}_i - \overline{\pmb{x}})^2} \times \sqrt{\sum\limits^n_{i=1}(\pmb{y}_i - \overline{\pmb{y}})^2}} similarity=corr(xx,yy)=i=1∑n(xxi−xx)2×i=1∑n(yyi−yy)2i=1∑n(xxi−xx)×(yyi−yy) - 皮尔逊相似度的计算结果在 [-1, 1]之间,-1 表示负相关,1 表示正相关。
- 皮尔逊相似度度量的是两个变量的变化趋势是否一致,不适合计算布尔值之间的相关度。
(3)杰卡德相似度 Jaccard
- 两个集合的交集元素个数 在 并集 中所占的比例,非常适用于布尔向量表示。
- 分子是 两个布尔向量做点积运算,得到的就是交集元素的个数;
- 分母是两个布尔向量做或运算,再求元素和。
2.3 协同过滤实现
2.3.1 通过杰卡德相似度计算推荐结果案例
import pandas as pd
import numpy as np
# 构建数据集,我们用1、0分别来表示用户的是否购买过该物品
users = ["User1", "User2", "User3", "User4", "User5"]
items = ["Item A", "Item B", "Item C", "Item D", "Item E"]
datasets = [
[1,0,1,1,0],
[1,0,0,1,1],
[1,0,1,0,0],
[0,1,0,1,1],
[1,1,1,0,1],
]
df = pd.DataFrame(datasets, columns=items, index=users)
print(df)
# 进行相似度计算
# 直接计算某两项的杰卡德相似系数
from sklearn.metrics import jaccard_score
# 计算Item A 和Item B的相似度
print(jaccard_score(df["Item A"], df["Item B"]))
# 计算所有的数据两两的杰卡德相似系数
from sklearn.metrics.pairwise import pairwise_distances
#pairwise_distances算的是杰卡德距离,1-pairwise_distances就是杰卡德相似度,默认是按行进行计算
# 计算用户间相似度
user_similar = 1 - pairwise_distances(df.values, metric="jaccard") # 返回一个包含DataFrame基础数据的numpy数组
user_similar = pd.DataFrame(user_similar, columns=users, index=users)
print("用户之间的两两相似度:")
print(user_similar)
# 计算物品间相似度
item_similar = 1 - pairwise_distances(df.T.values, metric="jaccard")
item_similar = pd.DataFrame(item_similar, columns=items, index=items)
print("物品之间的两两相似度:")
print(item_similar)
# 筛选 top-N相似结果,并进行推荐
# 基于用户的推荐
topN_users = {
}
# 遍历每一行数据
for i in user_similar.index:
# 取出每一列数据,并删除自身,然后排序数据
_df = user_similar.loc[i].drop([i])
_df_sorted = _df.sort_values(ascending=False) # ascending默认为True,即升序排列
top2 = list(_df_sorted.index[:2])
topN_users[i] = top2
print("Top2相似用户:")
print(topN_users)
# 构建推荐结果
rs_results = {
}
for user, sim_users in topN_users.items():
rs_result = set() # 存储推荐结果
for sim_user in sim_users:
# 构建初始的推荐结果
rs_result = rs_result.union(set(df.loc[sim_user].replace(0,np.nan).dropna().index)) # 把相似用户中的0替换成nan,并删除缺失值
# 过滤掉已经购买过的物品
rs_result -= set(df.loc[user].replace(0,np.nan).dropna().index)
rs_results[user] = rs_result
print("最终推荐结果:")
print(rs_results)
2.3.2 通过皮尔逊相关系数进行评分预测
采用皮尔逊相关系数进行相似度计算,要求用户-物品数据集是稠密矩阵。
import pandas as pd
import numpy as np
users = ["User1", "User2", "User3", "User4", "User5"]
items = ["Item A", "Item B", "Item C", "Item D", "Item E"]
# 用户购买记录数据集(评分矩阵)
datasets = [
[5, 3, 4, 4, None],
[3, 1, 2, 3, 3],
[4, 3, 4, 3, 5],
[3, 3, 1, 5, 4],
[1, 5, 5, 2, 1]
]
# 计算相似度:对于评分数据这里我们采用皮尔逊相关系数[-1,1]来计算,-1表示强负相关,+1表示强正相关
# pandas中的corr方法可直接用于计算皮尔逊相关系数
df = pd.DataFrame(datasets, columns=items, index=users)
# DataFrame是由多种类型的列构成的二维标签数据结构(二维数组),往往包含index(行标签)和columns(列标签)
print("用户之间的两两相似度:")
user_similar = df.T.corr() # 直接计算皮尔逊相关系数:默认是按列进行计算,因此如果计算用户间的相似度,需要进行转置
print(user_similar.round(4)) # 保留4位小数
print("物品之间的两两相似度:")
item_similar = df.corr()
print(item_similar.round(4))
基于用户间的相似度进行评分预测:考虑用户本身的评分以及近邻用户的加权平均相似度打分来进行预测。即:
预测评分 = ∑ i = 1 n 与近邻用户 i 的相似度 × 近邻用户 i 对该物品的打分 ∑ i = 1 n 与近邻用户 i 的相似度 预测评分 = \frac{\sum\limits^n_{i=1}与近邻用户i的相似度 \times 近邻用户i对该物品的打分}{\sum\limits^n_{i=1}与近邻用户i的相似度} 预测评分=i=1∑n与近邻用户i的相似度i=1∑n与近邻用户i的相似度×近邻用户i对该物品的打分例如:预测User1对ItemE的评分。
p r e d i c t = 0.8528 ∗ 3 + 0.7071 ∗ 5 0.8528 + 0.7071 = 3.91 predict = \frac{0.8528 * 3 + 0.7071 * 5}{0.8528 + 0.7071} = 3.91 predict=0.8528+0.70710.8528∗3+0.7071∗5=3.91
基于物品间的相似度进行评分预测:考虑物品本身的评分以及近邻物品的加权平均相似度打分来进行预测。即:
预测评分 = ∑ i = 1 n 与近邻物品 i 的相似度 × 该用户对近邻物品 i 的打分 ∑ i = 1 n 与近邻物品 i 的相似度 预测评分 = \frac{\sum\limits^n_{i=1}与近邻物品i的相似度 \times 该用户对近邻物品i的打分}{\sum\limits^n_{i=1}与近邻物品i的相似度} 预测评分=i=1∑n与近邻物品i的相似度i=1∑n与近邻物品i的相似度×该用户对近邻物品i的打分例如:预测User1对ItemE的评分。
p r e d i c t = 0.9695 ∗ 5 + 0.5817 ∗ 4 0.9695 + 0.5871 = 4.625 predict = \frac{0.9695 * 5 + 0.5817*4}{0.9695+0.5871} = 4.625 predict=0.9695+0.58710.9695∗5+0.5817∗4=4.625
2.4 基于模型的协同过滤推荐算法
前面介绍的直接计算相似度的协同过滤算法要求用户-物品评分矩阵必须是稠密的,这在实际的很多应用场景中是不现实的。对于用户-物品评分矩阵是稀疏的情况,我们采用基于模型的协同过滤算法。
基于模型的协同过滤算法的主要思想是:通过机器学习算法,在数据中找出模式,并将用户与物品间的互动方式模式化。
基于模型的协同过滤推荐算法:
- 基于分类算法、回归算法、聚类算法的CF
- 基于矩阵分解的CF
- 基于神经网络算法的CF
- 基于图模型的CF
2.4.1 基于图模型的协同过滤推荐算法
- 将用户的行为数据表示为二分图,然后根据这个二分图来为用户进行推荐。
- 根据两个顶点之间的路径数、路径长度 和 经过的顶点数来评价两个顶点的相关性。
2.4.2 基于矩阵分解的协同过滤推荐算法
- ALS交替最小二乘
- SVD奇异值分解
(1)ALS交替最小二乘
根据用户与物品的潜在表现,我们就可以预测用户对未评分物品的喜爱程度。
把原来的大矩阵,近似分解成两个小矩阵的乘积,这样在实际推荐计算时不再使用大矩阵,而是使用分解得到的两个小矩阵。具体的做法是:假设用户-物品评分矩阵 A A A 是 M × N M \times N M×N 维,即一共有 M M M个用户, N N N个物品。我们选一个很小的数 K ( K < < M , K < < N ) K(K<<M, K<<N) K(K<<M,K<<N)(这里的 K K K我们可以理解为是会影响到用户对物品评分的特征),通过计算得到两个矩阵 U , V U, V U,V 使得 U m × k V n × k T ≈ A m × n U_{m\times k}V_{n\times k}^T \approx A_{m\times n} Um×kVn×kT≈Am×n 。
ALS-WR(加权正则化交替最小二乘法):alternating-least-squares with weighted- λ \lambda λ-regularization ,该方法是将用户(user)对商品(item)的评分矩阵分解为两个矩阵,一个是用户对商品隐含特征的偏好矩阵,另一个是商品所包含隐含特征的矩阵。在这个矩阵分解的过程中,评分缺失项得到了填充,也就是说我们可以基于这个填充的评分矩阵来给用户做商品推荐了。
ALS的矩阵分解算法常应用于推荐系统中,将用户(user)对商品(item)的评分矩阵,分解为用户对商品隐含特征的偏好矩阵,和商品在隐含特征上的映射矩阵。
与传统的矩阵分解SVD方法来分解矩阵不同的是,ALS(alternating least squares)希望找到两个低维矩阵 U , V U, V U,V 使得 U m × k V n × k T ≈ A m × n U_{m\times k}V_{n\times k}^T \approx A_{m\times n} Um×kVn×kT≈Am×n 。这样就将问题的复杂度由 O ( m n ) O(mn) O(mn) 分解为了 O ( ( m + n ) k ) O((m+n)k) O((m+n)k) 。
怎样计算矩阵 U , V U, V U,V ?
首先用一个小于1的随机数初始化 V V V ,并根据公式( U V ≈ A UV\approx A UV≈A)求 U U U ,这样就得到了初始的 U , V U, V U,V 矩阵了。然后对损失函数进行优化,直至损失函数的值小于一个预设的数,或者迭代次数满足要求则停止。
3. 推荐系统评估
常用评估指标:
- 准确性
- 信任度
- 满意度
- 实时性
- 覆盖率
- 鲁棒性
- 多样性
- 可扩展性
- 新颖性
- 商业目标
- 惊喜度
- 用户留存
3.1 Exploitation & Exploration 探索与利用问题
- Exploitation(开发、利用):选择现在可能的最佳方案;
- Exploration(探测、搜索):选择现在不确定的一些方案,但未来可能会有高收益的方案。
在做两类决策的过程中,不断更新对所有决策的不确定性的认知,优化长期的目标。
EE问题实践:
- 兴趣扩展:相似话题,搭配推荐
- 人群算法:userCF用户聚类
- 平衡个性化推荐和热门推荐比例
- 随机丢弃用户历史行为
- 随机扰动模型参数
3.2 评估手段
离线评估和在线评估( 灰度发布、A/B测试)结合,定期做问卷调查。
参考:
[1] 推荐系统算法基础+综合项目实战(大牛老师主讲)