协同过滤算法(Collaborative Filtering,CF)

一、算法核心和原理

协同过滤算法核心步骤如下:
1)收集用户偏好;
2)找到相似的用户或物品;
3)计算并推荐。

算法原理:协同过滤算法是比较著名的推荐算法,主要功能是预测和推荐。算法通过对用户历史行为数据的挖掘发现用户的偏好,基于不同的偏好对用户进行群组划分并推荐品味相似的商品。

基于物品的协同过滤算法通过计算不同用户对不同物品的评分获得物品间的关系,基于物品间的关系对用户进行相似物品的推荐,评分即代表用户对物品的态度和偏好。比如,用户A同时购买了物品x,y,那么说明x,y之间的相关度高,当用户B也购买了物品x时,那么可以预测B也可能买物品y。

协同过滤算法是机器学习吗 协同过滤算法的原理_协同过滤算法是机器学习吗

1.收集用户偏好

在经济学研究中,会涉及到“经济个体偏好和效用”,经济个体的偏好差异会影响个人资源的分配,以求达到最优效用,但对经济个体的偏好如何收集却没有给出明确的答案。同理,在一个系统中,需要收集用户的偏好,然后根据用户的偏好计算相似度。一般可通用户行为来判断用户偏好,下面是几种常见的用户行为:

  • 评分:通过用户对物品的评分,可以精确的得到用户的偏好,如传统的星级评分制。
  • 投票:通过用户对物品的投票,可以精确的得到用户的偏好。转发:通过用户对内容的转发,可以精确的得到用户的偏好。
  • 评论:通过分析用户的评论,可以得到用户的情感:喜欢还是讨厌。
  • 点击:用户的点击一定程度上反映了用户的注意力,所以它也可以从一定程度上反映用户的喜好。
  • 购买:用户的购买是很明确的说明这个项目它感兴趣。以上都是比较通用的用户行为,我们可以给每个行为赋值,经过数据处理后,得出用户对物品的偏好。由于对用户行为的数据分析过程较为复杂,这里不展开讨论。

2.计算相似度

当我们已经知道用户的偏好后,可以根据用户的喜好计算相似用户和物品,然后基于相似用户或物品进行推荐,计算相似度的公式很多,这里选取其中一种介绍,Cosine 相似度(Cosine Similarity):

协同过滤算法是机器学习吗 协同过滤算法的原理_协同过滤算法是机器学习吗_02

补充:

协同过滤算法是机器学习吗 协同过滤算法的原理_相似度_03

注意:由于现实生活中买了物品却不评分的人大有人在如果按照余弦相似度计算会造成相似度十分小不利于后面进行推荐一次只选去计算用户都评分的物品来计算。

例如,小琴和小华对abcd这四种物品进行打分,小琴对abcd物品的评分为1、2、3、3,可以用向量表示:x(1,2,3,3);小华对abcd物品的评分为3、0、1、0,用向量表示:y(3,0,1,0)。把这两个数据代入到公式中去,可得到小华和小琴的相似度为:T(x,y)=(3x1+3x1)/10=0.6,即两者的相似度为0.6。值越大,两者的相似度越高。

3.计算并推荐。

推荐机制以上知道了相似度的计算方式,就可以基于相似度为用户进行推荐了,目前的推荐机制有两种方式:基于用户的CF(User CF)和基于物品的CF(Item CF):

基于用户的CF

基于用户的协同过滤,通过用户对不同内容(物品)的行为,来评测用户之间的相似性,找到“邻居”,基于这种相似性做出推荐。这种推荐的本质是,给相似的用户推荐其他用户喜欢的内容,这就是我们经常看到的:和你类似的人还喜欢如下内容。下面这个列子可以说明:

需要给用户A推荐游戏,根据用户B和用户C对游戏的偏好行为,给A推荐游戏,从下表可以知道,基于对游戏的偏好来讲,用户A跟用户C的相似度比用户跟用户B的相似度要大,所以,系统会给用户A推荐炉石传说。

当然,举的这个例子十分简单,实际上,还需要考虑的是每个用户物品的偏好程度,虽然用户A和用户C都玩过英雄联盟,但是用户A和用户C对英雄联盟的偏好程度可能不一样,在真正的计算过程中,需要对这种偏好的程度设定一个参数,参数的大小表明用户对物品的偏好程度的大小。根据设置或调整参数的大小,得出最后的值给用户推荐商品,这样的推荐计算结果会更加严谨。

协同过滤算法是机器学习吗 协同过滤算法的原理_英雄联盟_04

基于物品的CF

基于物品的CF的原理和基于用户的CF类似,只是在计算邻居时采用物品本身,而不是从用户的角度,即基于用户对物品的偏好找到相似的物品,然后根据用户的历史偏好,推荐相似的物品给用户。从计算的角度来看,就是将所有用户对某个物品的偏好作为一个向量来计算物品之间的相似度,得到物品的相似物品后,根据用户历史的偏好预测当前用户还没有表示偏好的物品,计算得到一个排序的物品列表作为推荐。就是我们常见的:购买该商品的用户还购买了如下商品,等等

也用相同的例子来说明:可以从下表看出,用户B和用户C有一个共同的特征,即选择了英雄联盟也会选炉石传说,说明这两个游戏之间相似度会比较高,那么会当用户A选择了英雄联盟,系统会把炉石传说也推荐给他。但是同时要注意的一点,这种情况也是属于比较理想化的一种,物品和物品之间的相似度可能不一样,也需要调整参数,这里不进行深入的探讨了。

协同过滤算法是机器学习吗 协同过滤算法的原理_相似度_05

代码(基于用户的)

import numpy as np
from  math import sqrt
a=np.float32(np.array([[3.0,5.0,0.0,4.0,0.0],
           [0.0,6.0,2.0,0.0,1.0],
           [0.0,0.0,5.0,2.0,0.0],
            [0.0,3.0,5.0,6.0,0.0],
            [1.0,0.0,0.0,8.0,0.0]]))
c= np.zeros((len(a), len(a)))
b=np.array(['A','B','C','D','E'])
b1=np.array(['a','b','c','d','e'])
#构造用户之间的相似矩阵
for i in range(len(a)):
  for j in range(len(a)):
    A=a[i]+a[j]
    D=[]
    d=[]
    for k in range(len(A)):
      if A[k]!=0 and A[k]!=a[i][k] and A[k]!=a[j][k]:
        c[i][j]=np.sum(a[i]*a[j])
        d.append(int(a[i][k]))
        D.append(int(a[j][k]))
    c[i][j]=c[i][j]/(sqrt(np.sum(np.array(d)**2))*sqrt(np.sum(np.array(D)**2)))
    if d==[]:
      c[i][j]=0
    if i==j:
      c[i][j]=0
print("用户相似矩阵")
print(np.array(c))
#推荐
a1=a.T
#print(a1)
for i in range(len(a)):
  a7=np.sum(a[i])/int(len(a[i]))
  print("对于:",b[i])
  d1=[]
  for j in range(len(a[i])):
    if a[i][j]==0:
      d1.append(j)
  result={}
  for k in d1:
    a[i][k]=(np.sum(a[i])/len(a[i]))+(np.sum(a1[k]*c[i])/np.sum(c[i]))#分值预测
    result[a[i][k]]=b1[k]
    print("可选:{},{}(对{}新评分)".format(b1[k],a[i][k],b1[k]))
  print("推荐:",result.get(max(result.keys())))
print('新评分矩阵')
print(a)

结果

用户相似矩阵
[[0. 1. 1. 0.90795938 0.86824314]
[1. 0. 1. 0.7592566 0. ]
[1. 1. 0. 0.87970651 1. ]
[0.90795938 0.7592566 0.87970651 0. 1. ]
[0.86824314 0. 1. 1. 0. ]]
对于: A
可选:c,5.455926418304443(对c新评分)
可选:e,3.7560017108917236(对e新评分)
推荐: c
对于: B
可选:a,2.88724946975708(对a新评分)
可选:d,6.202950954437256(对d新评分)
推荐: d
对于: C
可选:a,3.175198554992676(对a新评分)
可选:b,5.550542831420898(对b新评分)
可选:e,4.371014595031738(对e新评分)
推荐: b
对于: D
可选:a,5.255448341369629(对a新评分)
可选:e,6.1107282638549805(对e新评分)
推荐: e
对于: E
可选:b,6.294653415679932(对b新评分)
可选:c,8.196943283081055(对c新评分)
可选:e,9.489706993103027(对e新评分)
推荐: e
新评分矩阵
[[3. 5. 5.4559264 4. 3.7560017]
[2.8872495 6. 2. 6.202951 1. ]
[3.1751986 5.550543 5. 2. 4.3710146]
[5.2554483 3. 5. 6. 6.1107283]
[1. 6.2946534 8.196943 8. 9.489707 ]]