协同过滤(Collaborative Filtering)推荐算法是最经典、最常用的推荐算法。
所谓协同过滤, 基本思想是根据用户之前的喜好以及其他兴趣相近的用户的选择来给用户推荐物品(基于对用户历史行为数据的挖掘发现用户的喜好偏向, 并预测用户可能喜好的产品进行推荐),一般是仅仅基于用户的行为数据(评价、购买、下载等), 而不依赖于项的任何附加信息(物品自身特征)或者用户的任何附加信息(年龄, 性别等)。目前应用比较广泛的协同过滤算法是基于邻域的方法, 而这种方法主要有下面两种算法:
不管是UserCF还是ItemCF算法, 非常重要的步骤之一就是计算用户和用户或者物品和物品之间的相似度,以下介绍常用的相似性度量方法。
若用户和商品数量分别为 m , n m,n m,n的话,交互矩阵 A A A就是一个 m m m行 n n n列的矩阵。此时用户的相似度可以表示为(其中 u ⋅ v u\cdot v u⋅v指的是向量点积):
s i m u v = c o s ( u , v ) = u ⋅ v ∣ u ∣ ⋅ ∣ v ∣ sim_{uv} = cos(u,v) =\frac{u\cdot v}{|u|\cdot |v|} simuv=cos(u,v)=∣u∣⋅∣v∣u⋅v
上述用户-商品交互矩阵在现实情况下是非常的稀疏了,为了避免存储这么大的稀疏矩阵,在计算用户相似度的时候一般会采用集合的方式进行计算。理论上向量之间的相似度计算公式都可以用来计算用户之间的相似度,但是会根据实际的情况选择不同的用户相似度度量方法。
这个在具体实现的时候, 可以使用cosine_similarity进行实现:
from sklearn.metrics.pairwise import cosine_similarity
i = [1, 0, 0, 0]
j = [1, 0.5, 0.5, 0]
cosine_similarity([i, j])
两个用户 u u u和 v v v交互商品交集的数量占这两个用户交互商品并集的数量的比例,称为两个集合的杰卡德相似系数,用符号 s i m u v sim_{uv} simuv表示,杰卡德相似系数越大说明相识度越高。 s i m u v = ∣ u ∩ v ∣ ∣ u ∣ ∪ ∣ v ∣ sim_{uv}=\frac{|u \cap v|}{|u| \cup|v|} simuv=∣u∣∪∣v∣∣u∩v∣
由于杰卡德相似系数一般无法反映具体用户的评分喜好信息, 所以常用来评估用户是否会对某商品进行打分, 而不是预估用户会对某商品打多少分。
j u v = 1 − s i m u v = ∣ u ∣ ∪ ∣ v ∣ − ∣ u ∩ v ∣ ∣ u ∣ ∪ ∣ v ∣ j_{uv}=1-sim_{uv}=\frac{|u| \cup|v|-|u \cap v|}{|u| \cup|v|} juv=1−simuv=∣u∣∪∣v∣∣u∣∪∣v∣−∣u∩v∣
杰卡德距离用两个两个集合中不同元素占所有元素的比例来衡量两个集合的区分度。
jaccard相似度的缺点是值适用于二元数据的集合。
皮尔逊相关系数计算公式,其中 r u i , r v i r_{ui},r_{vi} rui,rvi分别表示用户 u u u和用户 v v v对商品 i i i是否有交互(或者具体的评分值), r ˉ u , r ˉ v \bar r_u, \bar r_v rˉu,rˉv分别表示用户 u u u和用户 v v v交互的所有商品交互数量或者具体评分的平均值。 s i m ( u , v ) = ∑ i ∈ I ( r u i − r ˉ u ) ( r v i − r ˉ v ) ∑ i ∈ I ( r u i − r ˉ u ) 2 ∑ i ∈ I ( r v i − r ˉ v ) 2 sim(u,v)=\frac{\sum_{i\in I}(r_{ui}-\bar r_u)(r_{vi}-\bar r_v)}{\sqrt{\sum_{i\in I }(r_{ui}-\bar r_u)^2}\sqrt{\sum_{i\in I }(r_{vi}-\bar r_v)^2}} sim(u,v)=∑i∈I(rui−rˉu)2∑i∈I(rvi−rˉv)2∑i∈I(rui−rˉu)(rvi−rˉv) 所以相比余弦相似度,皮尔逊相关系数通过使用用户的平均分对各独立评分进行修正,减小了用户评分偏置的影响。具体实现, 我们也是可以通过调包:
from scipy.stats import pearsonr
i = [1, 0, 0, 0]
j = [1, 0.5, 0.5, 0]
pearsonr(i, j)
上述介绍的余弦相似度计算方法比较常用,且一般效果也不会太差,但是对于评分数据不规范的时候,即存在有的用户喜欢打高分,有的用户喜欢打低分情况的时候,有的用户喜欢乱打分的情况,这时候consine相似度算出来的结果可能就不是那么准确了,比如下面这种情况:
这时候,如果用余弦相似度进行计算,会发现用户d和用户f比较相似,而实际上,如果看这个商品喜好的一个趋势的话,其实d和e比较相近,只不过e比较喜欢打低分,d比较喜欢打高分。所以对于这种用户评分偏置的情况,余弦相似度就不是那么好了,可以考虑使用皮尔逊相关系数。
更多的相似度度量方法:8种相似度度量方式的原理及实现
基于用户的协同过滤(以下用UserCF表示),思想其实比较简单,当一个用户A需要个性化推荐的时候, 我们可以先找到和他有相似兴趣的其他用户, 然后把那些用户喜欢的, 而用户A没有听说过的物品推荐给A。
下面将以一个具体例子理解UserCF
给用户推荐物品的过程可以形象化为一个猜测用户对商品进行打分的任务,上面表格里面是5个用户对于5件物品的一个打分情况,就可以理解为用户对物品的喜欢程度。
针对上述两个步骤,第一个步骤可以用相似度度量方法计算出用户之间的相似程度,第二个步骤则通过第一步骤中选出与Alice最相近的前N个用户,基于他们对物品5的评测估计出Alice的打分值。
P i , j = R ˉ i + ∑ k = 1 n ( S i , k ( R k , j − R ˉ k ) ) ∑ k = 1 n S j , k P_{i, j}=\bar{R}{i}+\frac{\sum{k=1}^{n}\left(S_{i, k}\left(R_{k, j}-\bar{R}{k}\right)\right)}{\sum{k=1}^{n} S_{j, k}} Pi,j=Rˉi+∑k=1nSj,k∑k=1n(Si,k(Rk,j−Rˉk))
所以这一种计算方式更为推荐。下面的计算将使用这个方式。
在获得用户 u u u对不同物品的评价预测后, 最终的推荐列表根据预测评分进行排序得到。 至此,基于用户的协同过滤算法的推荐过程完成。
1.首先计算Alice与其他用户的相似度(使用皮尔逊相关系数)
# 根据上图表格数据,可知各用户的向量为:Alice(5, 3, 4, 4), 用户1(3, 1, 2, 3), 用户2(4, 3, 4, 3),用户3(3, 3, 1, 5),用户4(1, 5, 5, 2)
from scipy.stats import pearsonr
i = [5, 3, 4, 4]
j = [3, 1, 2, 3]
print(pearsonr(i, j))
# 输出:
(0.8528028654224415, 0.14719713457755845)
这里我们使用皮尔逊相关系数, 也就是Alice与用户1的相似度是0.852。同样的方式, 我们就可以计算与其他用户的相似度, 这里可以使用numpy的相似度函数得到用户的相似性矩阵:
import numpy as np
users = np.array([[5, 3, 4, 4], [3, 1, 2, 3], [4, 3, 4, 3], [3, 3, 1, 5], [1, 5, 5, 2]])
print(np.corrcoef((users)))
# 输出:
[[ 1. 0.85280287 0.70710678 0. -0.79211803]
[ 0.85280287 1. 0.30151134 0.42640143 -0.88662069]
[ 0.70710678 0.30151134 1. -0.70710678 -0.14002801]
[ 0. 0.42640143 -0.70710678 1. -0.59408853]
[-0.79211803 -0.88662069 -0.14002801 -0.59408853 1. ]]
从上述结果可以看出,Alice用户和用户2,用户3,用户4的相似度是0.7,0,-0.79。 所以如果n=2, 找到与Alice最相近的两个用户是用户1,和Alice的相似度是0.85,用户2,和Alice相似度是0.7。
2.据相似度用户计算Alice对物品5的最终得分,用户1对物品5的评分是3,用户2对物品5的打分是5,那么根据上面的计算公式,可以计算出Alice对物品5的最终得分是4.87。
P A l i c e , 物 品 5 = R ˉ A l i c e + ∑ k = 1 2 ( S A l i c e , u s e r k ( R u s e r k , 物 品 5 − R ˉ u s e r k ) ) ∑ k = 1 2 S A l i c e , u s e r k = 4 + 0.85 ∗ ( 3 − 2.4 ) + 0.7 ∗ ( 5 − 3.8 ) 0.85 + 0.7 = 4.87 P_{Alice, 物品5}=\bar{R}_{Alice}+\frac{\sum{k=1}^{2}\left(S_{Alice,user k}\left(R_{userk, 物品5}-\bar{R}{userk}\right)\right)}{\sum{k=1}^{2} S_{Alice, userk}}=4+\frac{0.85*(3-2.4)+0.7*(5-3.8)}{0.85+0.7}=4.87 PAlice,物品5=RˉAlice+∑k=12SAlice,userk∑k=12(SAlice,userk(Ruserk,物品5−Rˉuserk))=4+0.85+0.70.85∗(3−2.4)+0.7∗(5−3.8)=4.87
3.根据用户评分对用户进行推荐 以上,我们就得到了Alice对物品5的得分是4.87,根据Alice的打分对物品排个序从大到小: 物 品 1 > 物 品 5 > 物 品 3 = 物 品 4 > 物 品 2 物品1>物品5>物品3=物品4>物品2 物品1>物品5>物品3=物品4>物品2 这时候,如果要向Alice推荐2款产品的话,我们就可以推荐物品1和物品5给Alice。
由于UserCF技术上的两点缺陷, 导致很多电商平台并没有采用这种算法, 而是采用了ItemCF算法实现最初的推荐系统。
基于物品的协同过滤(ItemCF)的基本思想是预先根据所有用户的历史偏好数据计算物品之间的相似性,然后把与用户喜欢的物品相类似的物品推荐给用户。比如物品a和c非常相似,因为喜欢a的用户同时也喜欢c,而用户A喜欢a,所以把c推荐给用户A。ItemCF算法并不利用物品的内容属性计算物品之间的相似度, 主要通过分析用户的行为记录计算物品之间的相似度, 该算法认为, 物品a和物品c具有很大的相似度是因为喜欢物品a的用户大都喜欢物品c。
import numpy as np
# 根据上图表格数据,可知各物品的向量为:物品1(3, 4, 3, 1), 用户1(1, 3, 3, 5), 用户2(2, 4, 1, 5),用户3(3, 3, 5, 2),用户4(3, 5, 4, 1)
items = np.array([[3, 4, 3, 1], [1, 3, 3, 5], [2, 4, 1, 5], [3, 3, 5, 2], [3, 5, 4, 1]])
print(np.corrcoef((items)))
# 输出
[[ 1. -0.64888568 -0.43528575 0.47368421 0.96945842]
[-0.64888568 1. 0.67082039 -0.32444284 -0.47809144]
[-0.43528575 0.67082039 1. -0.8705715 -0.42761799]
[ 0.47368421 -0.32444284 -0.8705715 1. 0.58167505]
[ 0.96945842 -0.47809144 -0.42761799 0.58167505 1. ]]
P A l i c e , 物 品 5 = R ˉ 物 品 5 + ∑ k = 1 2 ( S 物 品 5 , 物 品 k ( R A l i c e , 物 品 k − R ˉ 物 品 k ) ) ∑ k = 1 2 S 物 品 k , 物 品 5 = 13 4 + 0.97 ∗ ( 5 − 3.2 ) + 0.58 ∗ ( 4 − 3.4 ) 0.97 + 0.58 = 4.6 P_{Alice, 物品5}=\bar{R}{物品5}+\frac{\sum{k=1}^{2}\left(S_{物品5,物品 k}\left(R_{Alice, 物品k}-\bar{R}{物品k}\right)\right)}{\sum{k=1}^{2} S_{物品k, 物品5}}=\frac{13}{4}+\frac{0.97*(5-3.2)+0.58*(4-3.4)}{0.97+0.58}=4.6 PAlice,物品5=Rˉ物品5+∑k=12S物品k,物品5∑k=12(S物品5,物品k(RAlice,物品k−Rˉ物品k))=413+0.97+0.580.97∗(5−3.2)+0.58∗(4−3.4)=4.6
因此,我们可以推荐物品5给Alice。
· | UserCF | ItemCF |
---|---|---|
适用场景 | 时效性强,用户个性化兴趣不太明显的领域 | 长尾物品丰富,用户个性化需求强烈的领域 |
· | 用户较少的场合:新闻推荐 | 物品数远小于用户数的场合:图书、电子商务和电影网站 |
注重点 | 兴趣相似的小群体的热点 | 维系用户的历史兴趣 |
用户交互特点 | 用户有新行为,不一定造成推荐结果的立即变化 | 推荐结果的实时变化 |
缺点 | 计算复杂度–用户数量的增长:近似于平方关系,推荐结果解释性不强 | 推荐结果解释性强 |
由于UserCF和ItemCF结果评估部分是共性知识点, 所以在这里统一标识。 这里介绍评测指标:
协同过滤算法存在的问题之一就是泛化能力弱, 即协同过滤无法将两个物品相似的信息推广到其他物品的相似性上。 导致的问题是热门物品具有很强的头部效应, 容易跟大量物品产生相似, 而尾部物品由于特征向量稀疏, 导致很少被推荐。 比如下面这个例子:
A, B, C, D是物品, 看右边的物品共现矩阵, 可以发现物品D与A、B、C的相似度比较大, 所以很有可能将D推荐给用过A、B、C的用户。 但是物品D与其他物品相似的原因是因为D是一件热门商品, 系统无法找出A、B、C之间相似性的原因是其特征太稀疏, 缺乏相似性计算的直接数据。 所以这就是协同过滤的天然缺陷:推荐系统头部效应明显, 处理稀疏向量的能力弱。
为了解决这个问题, 同时增加模型的泛化能力,2006年,矩阵分解技术(Matrix Factorization,MF)被提出, 该方法在协同过滤共现矩阵的基础上, 使用更稠密的隐向量表示用户和物品, 挖掘用户和物品的隐含兴趣和隐含特征, 在一定程度上弥补协同过滤模型处理稀疏矩阵能力不足的问题。
此外协同过滤的特点就是完全没有利用到物品本身或者是用户自身的属性,仅仅利用了用户与物品的交互信息就可以实现推荐,比较简单高效,但这也是它的一个短板所在,由于无法有效的引入用户年龄, 性别,商品描述,商品分类,当前时间,地点等一系列用户特征、物品特征和上下文特征,这就造成了有效信息的遗漏,不能充分利用其它特征数据。
为了解决这个问题, 在推荐模型中引用更多的特征,推荐系统慢慢的从以协同过滤为核心到了以逻辑回归模型为核心, 提出了能够综合不同类型特征的机器学习模型。
参考资料